ในกระบวนการเพื่อระบุหาการมีอยู่ของมัลแวร์สภาพแวดล้อมที่เป็น Windows โปรแกรมในกลุ่ม anti malware มีการใช้เทคนิคหลายอย่างร่วมกันเพื่อให้แน่ใจว่าหากมีการ bypass เทคนิคใดเทคนิคหนึ่งแล้ว เทคนิคอื่นจะยังคงอยู่เพื่อทำให้การตรวจจับยังมีประสิทธิภาพ เราอาจรู้จักวิธีการที่ถูกใช้เหล่านี้ในชื่อต่าง ๆ อาทิ การทำ API hooking เพื่อตรวจหาการเรียกใช้ฟังก์ชันของระบบที่ผิดปกติ, การใช้ Event tracing for Windows (ETW) เพื่อรับข้อมูลการทำงานของระบบปฏิบัติการแล้วนำมาประมวลผล, การติดตั้งไดร์เวอร์เพื่อคอยดักจับเหตุการณ์ในระดับเคอร์เนลล์ รวมไปถึงการผสานเข้ากับฟีเจอร์บางอย่างที่ระบบปฏิบัติการมีให้เพื่อให้ได้มุมมองที่กว้างและลึกขึ้นอย่าง Antimalware Scan Interface (AMSI)

เมื่อมองกลับมาในมุมของการ bypass แล้ว การ bypass ก็มักจะเกิดขึ้นเพื่อตอบสนองต่อแนวทางการตรวจจับที่เฉพาะ ตัวอย่างเช่นการโจมตีในกลุ่ม Tampering attack ที่พุ่งเป้าไปที่กระบวนการซึ่งเกิดขึ้นเมื่อโปรเซสกำลังจะถูกสร้างมาจากไฟล์ เพื่อให้การเกิดขึ้นของโปรเซสนั้นไม่ถูกระบุโดยโปรแกรม Anti malware ว่าเป็นอันตราย เทคนิค Process Ghosting ซึ่งเราจะมาพูดถึงกันในวันนี้ก็คือหนึ่งเทคนิคในกลุ่มนี้

Tampering Attacks

ก่อนจะไปพูดถึงเมนูหลักของเราคือ Process Ghosting การแนะนำการโจมตีในกลุ่ม Tampering attack ให้ได้รู้จักกันโดยคร่าวก่อนอาจเป็นจุดเริ่มต้นที่ทำให้เราเข้าใจเทคนิคการโจมตีในลักษณะนี้ได้ดีมากยิ่งขึ้น

เทคนิคการโจมตีในกลุ่ม Tampering ซึ่งถูกค้นพบมาก่อนและมีอิทธิพลต่อการค้นพบ Process Ghosting มีอยู่ทั้งหมด 3 เทคนิค ได้แก่ Process Doppelgänging, Process Herpaderping และ Process reimaging

Process Doppelgänging

Process Doppelgänging เป็นเทคนิคการโจมตีที่อาศัยฟีเจอร์ของ Windows ในการทำไฟล์ซึ่งควรจะถูกนำมาสร้างเป็นโปรเซสนั้นไม่ปรากฎเมื่อถูกค้นหา

Process Doppelgänging อาศัยกลไกที่มีชื่อว่า Windows Transactional NTFS (TxF) ซึ่งทำให้ผู้ใช้งานสามารถสร้างสิ่งที่เรียกว่า atomic transaction บนระบบ NTFS ได้เช่นเดียวกับคอนเซ็ปต์ของ transaction ที่มีในฐานข้อมูล

ในการใช้เพื่อโจมตี ผู้โจมตีจะสร้างส่วนของไฟล์ที่เรียกว่าอิมเมจซึ่งจะถูกนำไปใช้ในการสร้างเป็นโปรเซสต่อ โดยอิมเมจทที่ถูกสร้างนั้นจะถูกสร้างจากไฟล์ที่อยู่ใน transaction ซึ่งจะถูก roll back (หนึ่งในคุณสมบัติของ transaction) หลังจากที่มีการสร้างอิมเมจเสร็จสิ้น ซึ่งจะทำให้ไฟล์ไม่ปรากฎในระบบไฟล์ และส่งผลให้เมื่อมีการนำอิมเมจไปสร้างเป็นโปรเซส ความพยายามในการระบุหาไฟล์ที่เชื่อมโยงกับโปรเซสจะไม่สามารถทำได้

Process Herpaderping

Process Herpaderping เป็นเทคนิคการโจมตีที่จะทำให้ความพยายามในการระบุหาไฟล์ที่เชื่อมโยงกับโปรเซสนั้นปรากฎผลลัพธ์เป็นไฟล์อื่น

อ้างอิงจากกระบวนการโดยทั่วไปของการเกิดขึ้นของโปรเซส ไฟล์ executable จะถูกเรียก/เปิด หลังจากนั้น handle ที่เกิดจากการเรียกไฟล์จะถูกระบุกับฟังก์ชันของระบบเพื่อสร้างเป็นอิมเมจที่จะถูกเอาไปสร้างเป็นโปรเซสต่อ Process Herpaderping จะอาศัย handle ที่ยังค้างอยู่ในหลังจากที่มีการสร้างอิมเมจแล้วในการเขียนทับไฟล์ executable ด้วยไฟล์ที่ไม่เป็นอันตราย ซึ่งส่งผลให้ไฟล์ที่ถูกเขียนใหม่และปรากฎบนดิสก์นั้นเป็นคนละไฟล์กับที่ถูกโหลดเข้าสู่หน่วยความจำ และทำให้การเชื่อมโยงไฟล์กับโปรเซสได้ผลลัพธ์ที่ไม่ถูกต้อง

Process Reimaging

Process Reimaging เป็นเทคนิคการโจมตีที่อาศัยการโจมตีปัญหาของการ synchronize cache ที่เกิดขึ้นในเคอร์เนล ผลลัพธ์ของ Process Reimaging จะทำให้พาธของไฟล์ executable ในระบบไฟล์กับพาธของไฟล์ executable ที่อิมเมจมีการอ้างถึงนั้นไม่ตรงกัน การใช้เทคนิค Process Reimaging สามารถทำได้ง่าย ๆ ด้วยการโหลดไฟล์ DLL ในพาธที่เป็นเหยื่อล่อ, ถอนการโหลดไฟล์ DLL ออก และทำการโหลดไฟล์ DLL ที่พาธใหม่ การดำเนินการในลักษณะนี้เมื่อถูกตรวจสอบโดยฟังก์ชันของระบบบางฟังก์ชันจะได้ผลลัพธ์เป็นพาธเหยื่อล่อ

Process Ghosting

แนวคิดหลักของเทคนิค Process Ghosting คือการเรียก executable ที่ถูกลบไปแล้วซึ่งจะทำให้การเชื่อมโยงเพื่อตรวจสอบไฟล์และโปรเซสนั้นไม่สามารถทำได้

อ้างอิงจากต้นฉบับของงานวิจัย เทคนิค Process Ghosting สามารถทำได้ตามขั้นตอนดังนี้

  • ผ่านฟังก์ชัน NtCreateFile (อาจใช้เป็นฟังก์ชันที่เกี่ยวข้องกับการเปิดไฟล์แทนได้ เช่น NtOpenFile)
    • กำหนด flag FILE_SUPERSEDED ใน IoStatusBlock ความหมายของการกำหนด flag นี้กับไฟล์ที่มีอยู่แล้วจะหมายถึงการลบไฟล์ปัจจุบันและทำการสร้างไฟล์ใหม่
    • กำหนด flag FILE_DELETE_ON_CLOSE ใน CreateOptions ความหมายของการกำหนด flag นี้จะหมายถึงให้การลบไฟล์ทันทีหาก handle สุดท้ายที่เกี่ยวข้องกับไฟล์ทุกปิด (มีการเรียกใช้ฟังก์ชัน NtClose กับ handle ของไฟล์
NTSTATUS stat = NtOpenFile(&file, 
    DELETE | SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE,
    &attr, 
    &status_block, 
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    FILE_SUPERSEDE | FILE_SYNCHRONOUS_IO_NONALERT
);
  • ผ่านฟังก์ชัน CreateFileW (อาจใช้เป็นฟังก์ชันที่เกี่ยวข้องกับการเปิดไฟล์แทนได้ เช่น OpenFile)
    • กำหนด flag CREATE_ALWAYS ใน dwCreationDisposition เพื่อให้มีการสร้างไฟล์ใหม่เสมอแม้จะมีไฟล์เดิมอยู่ ซึ่งหากมีไฟล์เดิม การกำหนด flag จะเท่ากับการสร้างไฟล์ใหม่ทับไฟล์เดิม
    • กำหนด flag FILE_FLAG_DELETE_ON_CLOSE ใน dwFlagAndAttributes เช่นเดียวกับ FILE_DELETE_ON_CLOSE ในกรณีของ NtCreateFile การกำหนด flag นี้จะหมายถึงกำหนดให้ไฟล์ถูกลบทันทีหาก handle ที่เกี่ยวข้องกับไฟล์ดังกล่าวถูกปิด
  • หลังจากมีการกำหนด flag ทั้งในกรณีที่มีการเรียกใช้ NtCreateFile หรือในกรณีที่มีการเรียกใช้ CreateFileW เสร็จแล้ว ให้ทำการเรียกใช้ฟังก์ชัน NtSetInformationFile ที่มีการระบุคลาส FileDispositionInformation เอาไว้ คลาส FileDispositionInformation ที่อ้างอิงมาจากสตรัคเจอร์ FILE_DISPOSITION_INFORMATION จะต้องมีการกำหนดค่าในฟิลด์ DeleteFile ให้เป็น TRUE ด้วย
FILE_DISPOSITION_INFORMATION info = { 0 };
info.DeleteFile = TRUE;
NtSetInformationFile(
    hDelFile,
    &status_block,
    &info,
    sizeof(info),
    FileDispositionInformation
);
  • ทำการเขียนไฟล์จาก handle ของไฟล์ที่เราได้มาจาก NtCreateFile หรือ CreateFileW ด้วยโค้ด(ของมัลแวร์)ที่เราต้องการ
status = NtWriteFile(
        hDelFile,
        NULL,
        NULL,
        NULL, 
        &status_block,
        payladBuf, 
        payloadSize,
        &ByteOffset,
        NULL
);
  • เตรียมการสร้างโปรเซสด้วยการสร้างอิมเมจจากไฟล์ที่จะเป็นวัตถุดิบในการสร้างโปรเซสก่อนด้วยฟังก์ชัน NtCreateSection ในขั้นตอนนี้หากการสร้างอิมเมจสมบูรณ์ เราจะได้ handle ของอิมเมจมาเพื่อใช้สร้างโปรเซสต่อ
HANDLE hSection = nullptr;
status = NtCreateSection(&hSection,
    SECTION_ALL_ACCESS,
    NULL,
    0,
    PAGE_READONLY,
    SEC_IMAGE,
    hDelFile
);
  • ก่อนจะทำการสร้างโปรเซส เรียกใช้ฟังก์ชัน NtClose เพื่อปิด handle ที่เกิดจาก NtCreateFile หรือ CreateFileW อ้างอิงจาก flag ที่เรากำหนดไว้ในขั้นตอนก่อนหน้า เมื่อมีการปิด handle ที่เกี่ยวข้องกับไฟล์แล้ว ไฟล์ที่ handle นี้เชื่อมโยงจะถูกลบ
  • นำ handle ของอิมเมจที่ได้จากการเรียกใช้ฟังก์ชัน NtCreateSection ไปสร้างเป็นโปรเซสต่อ โดยอาจใช้ฟังก์ชันอย่าง NtCreateProcessEx แล้วทำการระบุพารามิเตอร์ในส่วน sectionHandle เป็น handle ของอิมเมจที่เรามีอยู่
NTSTATUS status = NtCreateProcessEx(
    &hProcess,
    PROCESS_ALL_ACCESS,
    NULL,
    NtCurrentProcess(),
    PS_INHERIT_HANDLES,
    hSection,
    NULL,
    NULL,
    FALSE
);

สิ่งที่เราทำในขั้นตอนที่ผ่านมาทั้งหมดนั้นมีใจความสำคัญคือการสร้างไฟล์ที่มีสถานะ “กำลังจะถูกลบ” ติดอยู่ และทำการลบทันที “เมื่อมีการสร้าง section ที่เป็นอิมเมจ ก่อนที่จะนำอิมเมจไปสร้างเป็นโปรเซส”

หากอ้างคำพูดในรีเสิร์ชต้นฉบับ โปรเซสซึ่งเหมือนกับวิญญาณนั้นถูกสร้างจากไฟล์ซึ่งเหมือนกับร่างที่กำลังจะตาย (ถูกลบ) เทคนิคนี้จึงถูกเรียกว่า Process Ghosting

ในมุมของการพยายามตรวจสอบและเชื่อมโยงโปรเซสที่เกิดขึ้นใหม่กลับไปยังไฟล์โดยโปรแกรม Anti malware หากความพยายามในการตรวจสอบเกิดขึ้นหลังจากไฟล์ถูกลบออกไปแล้ว นั่นหมายถึงโปรแกรม Anti malware จะไม่เจอไฟล์ที่เชื่อมโยงกับโปรเซส และทำให้โปรแกรม Anti malware ไม่สามารถตรวจสอบได้

Proof of Concept

เทคนิค Process Ghosting มีการถูกอิมพลีเมนต์ให้พร้อมใช้งานจริงแล้วโดย hasherezade สามารถดูเพิ่มเติมได้ที่ hasherezade/proess_ghosting