Code Note คือชุดของบล็อกและโพสต์ซึ่งจะนำโค้ดจากโครงการโอเพนซอร์สมาทำการวิเคราะห์และทำความเข้าใจ ให้ความหมายและข้อเสนอตามจุดประสงค์ของแต่ละโครงการ

Code Note ฉบับแรกที่ 0x1 จะขอเริ่มต้นด้วยโค้ดจากโครงการ DeathRansom ซึ่งเป็นโครงการมัลแวร์เรียกค่าไถ่ที่ผู้พัฒนาชื่อ ReddyyZ มีการนำซอร์สโค้ดของโครงการมาเผยแพร่บน GitHub และไม่ได้มีระบุจุดประสงค์อย่างชัดเจนถึงการปล่อยซอร์สโค้ดในลักษณะนี้

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

รายละเอียดหัวข้อย่อยใน Code Note 0x1: DeathRansom มีตามรายการด้านล่างครับ

Project Overiew

ข้อมูลจาก GitHub แสดงให้เห็นว่าโครงการนี้ทั้งหมดถูกพัฒนาด้วยโค้ดในภาษา Python เวอร์ชัน 2 และ 3 โครงการนี้มีโครงสร้างของไฟล์และไดเรกทอรีตามแผนภาพด้านล่างครับ

.
├── LICENSE
├── README.md
├── Ransom Request
│   ├── main.py
│   ├── main.ui
│   ├── resources.qrc
│   └── resources_rc.py
├── deathransom.py
├── modules
│   ├── __init__.py
│   ├── bypass
│   │   ├── __init__.py
│   │   ├── anti_debugger.py
│   │   ├── anti_sandbox.py
│   │   └── anti_vm.py
│   ├── generate_key.py
│   ├── learn_key.py
│   └── rsa.py
├── requirements.txt
└── time_script.py

การตรวจสอบไฟล์แต่ละรายการที่ปรากฎในโครงสร้างของโครงการทำให้เรารู้หน้าที่และจุดประสงค์ของโค้ดที่อยู่ในไฟล์ ได้แก่

  • ไฟล์ในไดเรกทอรี Ransom Request รับผิดชอบการแสดงหน้าต่าง ransom note หลังจากที่ DeathRansom ดำเนินการเสร็จ
    • ไฟล์ main.py จัดเก็บโค้ดซึ่งควบคุมลักษณะของหน้าต่าง ransom note โดยการใช้ PyQt เป็นผลมาจากการนำไฟล์ main.ui มาทำการแปลง
    • ไฟล์ main.ui โค้ดใน XML ซึ่งเป็นผลลัพธ์มาจากการใช้ Qt Designer
    • ไฟล์ resources.qrc เก็บการอ้างอิงไปยัง resource อื่นๆ ที่ใช้ในโครงการ
    • ไฟล์ resources_rc.py โค้ดซึ่งจัดเก็บข้อมูล resource จริงๆ ในลักษณะไบนารีของโครงการเอาไว้ เป็นผลมาจากการนำไฟล์ resources.qrc มาทำการแปลง
  • ไฟล์ deathransom.py จัดเก็บโค้ดการทำงานหลักของ DeathRansom โดยประกอบไปด้วยโค้ดซึ่งสั่งการให้ฟังก์ชัน Anti-analysis ทำงาน, โค้ดที่ทำให้มีการสร้างกุญแจสำหรับเข้ารหัสและทำการเข้ารหัสไฟล์ และโค้ดที่สั่งการฟังก์ชันซึ่งรับผิดชอบการสร้าง ransom note
  • ไฟล์ในไดเรกทอรี modules: จัดเก็บโค้ดซึ่งเป็นโมดูลอื่นๆ ของ DeathRansom
    • ไฟล์ในไดเรกทอรี bypass: จัดเก็บโค้ดที่เกี่ยวกับการ Anti-analysis
      • ไฟล์ anti_debugger.py โค้ดสำหรับตรวจจับว่ามีการใช้งาน debugger อยู่หรือไม่ผ่านฟังก์ชัน IsDebuggerPresent()
      • ไฟล์ anti_sandbox.py รวมฟังก์ชันการตรวจจับว่าโค้ดทำงานอยู่ใน sandbox หรือไม่
      • ไฟล์ anti_vm.py เก็บฟังก์ชันการตรวจจับว่าโค้ดทำงานอยู่ใน virtualized environment หรือไม่
    • ไฟล์ generate_key.py เป็นไฟล์ซึ่งเก็บชุดคำสั่งสำหรับสร้างคู่กุญแจด้วยอัลกอริธึม RSA แบบ 4096 บิต
    • ไฟล์ learn_key.py เก็บฟังก์ชันซึ่งสร้าง HTTP GET request ไปยังพาธบนอินเตอร์เน็ตเพื่อเอาข้อมูลกุญแจสาธารณะของผู้พัฒนามัลแวร์
    • ไฟล์ rsa.py เก็บฟังก์ชันสำหรับกระบวนการเข้ารหัสไฟล์
  • ไฟล์ time_script.py: เก็บโค้ดจับเวลาซึ่งจะทำการลบไฟล์ที่ถูกเข้ารหัสเมื่อถึงเวลาที่กำหนด

อ้างอิงจากไฟล์ README.md กระบวนการ build โครงการนี้จะประกอบไปด้วยขั้นตอนดังต่อไปนี้

  1. ลง dependencies ตามที่ปรากฎในไฟล์ requirements.txt และลง PyQt5
  2. ผู้ควบคุมมัลแวร์ทำการสร้างคู่กุญแจสาธารณะ และทำการอัปโหลดกุญแจสาธารณะไปยังบริการซึ่งมัลแวร์สามารถเข้าไปอ่านค่าของกุญแจสาธารณะได้ และให้เปลี่ยนตำแหน่งภายในสคริปต์ให้สอดคล้องกับตำแหน่งที่อัปโหลดไฟล์ไปไว้ด้วย
  3. ใช้โมดูล pyinstaller ในการเปลี่ยนโค้ดในภาษาไพธอนไปเป็นไฟล์ portable executable โดยต้องเปลี่ยนทั้งไฟล์ time_script.py และ main.py ในพาธ Ransom Request
  4. อัปโหลดไฟล์ portable executable จากขั้นตอนที่ 3 ไปไว้ในบริการอัปโหลดไฟล์ที่มัลแวร์สามารถดาวโหลดมาแสดงได้ แก้ไขสคริปต์เพื่อระบุพาธที่จะให้มัลแวร์ทำการดาวโหลด
  5. ใช้โมดูล pyinstaller ในการเปลี่ยนโค้ดในภาษาไพธอนของไฟล์ deathransom.py ไปเป็นไฟล์ portable executable และนำผลลัพธ์ที่ได้ไปเอ็กซีคิวต์ในระบบเป้าหมาย

Functions

Anti-Analysis

ฟังก์ชัน anti_disassembly() ยังไม่มีลักษณะของโค้ดที่ป้องกันการถูก disassembly ได้จริง

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

  1. ใช้การตรวจสอบหาโปรเซสจากรายการของโปรเซสที่มักพบใน sandbox หรือที่เกี่ยวข้องกับการวิเคราะห์มัลแวร์ด้วยฟังก์ชัน check_sandbox_in_process() กระบวนการนี้ใช้การตรวจสอบจากผลของการใช้คำสั่ง tasklist ไม่ได้เป็นการตรวจสอบจากผลลัพธ์ของการใช้ WinAPI
def check_sandbox_in_process():
    EvidenceOfSandbox = []
    sandbox_processes = "vmsrvc", "tcpview", "wireshark", "visual basic", "fiddler", "vmware", "vbox", "process explorer", "autoit", "vboxtray", "vmtools", "vmrawdsk", "vmusbmouse", "vmvss", "vmscsi", "vmxnet", "vmx_svga", "vmmemctl", "df5serv", "vboxservice", "vmhgfs", "vmtoolsd"
    runningProcess = []
    for item in os.popen("tasklist").read().splitlines()[4:]:
        runningProcess.append(item.split())
    for process in runningProcess:
        for sandbox_process in sandbox_processes:
            if sandbox_process in process:
                if process not in EvidenceOfSandbox:
                    EvidenceOfSandbox.append(process)
                    break

    if not EvidenceOfSandbox:
        return True
    else:
        return False
  1. ฟังก์ชัน check_sleep_acceleration() ทำงานและส่งผลให้มัลแวร์จะหยุดกระบวนการทำงานเป็นเวลา 60 วินาที หลังจากช่วงเวลาดังกล่าวแล้วมัลแวร์จะทำการตรวจสอบเวลาจากเซิร์ฟเวอร์ NTP เพื่อระบุหาการทำ sleep acceleration ของ sandbox

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

  1. ฟังก์ชัน display_prompt() ทำงาน โดยฟังก์ชันนี้มีสมมติฐานว่าในสภาพแวดล้อมซึ่งเป็น sandbox นั้นจะไม่มีการควบคุมจากผู้ใช้งาน ฟังก์ชันนี้จึงรับหน้าที่ในการสร้างหน้าต่าง pop-up ขึ้นมาและตรวจสอบว่าเกิดการมีปฏิสัมพันธ์กับหน้าต่างนี้หรือไม่
  2. ฟังก์ชัน check_idle_time() ทำงาน ฟังก์ชันนี้ใช้สมมติฐานเดียวกับฟังก์ชัน display_prompt() คือการตรวจสอบว่าภายในช่วงเวลาที่กำหนดนั้น ผู้ใช้งานมีปฏิสัมพันธ์กับระบบใดไม่ว่าจะเป็นลักษณะใดๆ หรือไม่ โดยมัลแวร์มีการกำหนดไว้ว่าผู้ใช้งานจะต้องมีปฏิสัมพันธ์ใดๆ กับระบบในช่วงระยะเวลาไม่เกิน 60 วินาที
  3. ฟังก์ชัน check_click() ทำงาน ฟังก์ชันใช้วิธีการตรวจสอบจำนวนการคลิกเมาส์ที่เกิดขึ้นเพื่อยืนยันว่าผู้ใช้งานมีปฏิสัมพันธ์กับระบบ โดยมีเงื่อนไขว่าผู้ใช้งานจะต้องคลิกเป็นจำนวน 10 ครั้งมัลแวร์ถึงจะเริ่มทำงาน
  4. ฟังก์ชัน check_cursor_pos() ทำงาน ฟังก์ชันนี้ตรวจสอบว่ามีการเลื่อนของเคอร์เซอร์หรือไม่เพื่อระบุการมีปฏิสัมพันธ์ของผู้ใช้กับระบบ

ในส่วนต่อมามัลแวร์จะเรียกใช้ฟังก์ชัน anti_debugger.check() เพื่อตรวจสอบหาการมีอยู่ของ debugger ผ่านทางการเรียกใช้ฟังก์ชัน windll.kernel32.IsDebuggerPresent()

ฟังก์ชัน anti_vm.check() ทำงานเป็นฟังก์ชันสุดท้าย โดยฟังก์ชันใช้วืธีการระบุว่าโปรแกรมมัลแวร์ทำงานอยู้ใน virtualized environment หรือไม่ด้วยการตรวจสอบ MAC address ของเน็ตเวิร์กอินเตอร์เฟสว่ามีค่าตรงกับรายการที่ฝังมากับมัลแวร์หรือไม่ ค่า MAC address เหล่านี้โดยส่วนใหญ่เป็นของ MAC address ของซอฟต์แวร์ virtualization ซึ่งค่อนข้างตายตัวทั้งหมด

Files Encryption

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

valid_extension = [".pl",".7z",".rar",".m4a",".wma",".avi",".wmv",".d3dbsp",".sc2save",".sie",".sum",".bkp",".flv",".js",".raw",".jpeg",".tar",".zip",".tar.gz",".cmd",".key",".DOT",".docm",".txt", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".odt", ".jpg", ".png", ".csv", ".sql", ".mdb", ".sln", ".php", ".asp", ".aspx", ".html", ".xml", ".psd", ".bmp"]

มัลแวร์จะไม่เข้ารหัสไฟล์ที่ปรากฎนามสกุลไฟล์เป็น .wannadie ซึ่งหมายถึงไฟล์ที่ถูกเข้ารหัสโดย DeathRansom ไปแล้ว

กระบวนการเข้ารหัสไฟล์จะเริ่มต้นโดยการเรียกใช้ฟังก์ชัน rsa.encryptar() ซึ่งมีการระบุพารามิเตอร์ 2 รายการ ได้แก่ พาธของไฟล์และค่ากุญแจสาธารณะของผู้โจมตีซึ่งถูกดาวโหลดมาจากอินเตอร์เน็ต

def encryptar(FileName,public_key):
    try:
        public_key = RSA.importKey(public_key)
        encryptor = PKCS1_OAEP.new(public_key)
        OutputFile = os.path.join(os.path.dirname(FileName), "(encrypted)" + os.path.basename(FileName) + '.wannadie')
        with open(FileName,'rb') as initial_file:
            text = initial_file.read()
            initial_file.close()
            encrypted = encryptor.encrypt(text)
        with open(FileName,'wb') as output_file:
            output_file.write(encrypted)
            output_file.close()
        os.rename(FileName,OutputFile)
        return True
    except:
        return False

ภายใต้ฟังก์ชัน rsa.encryptar() มัลแวร์เรียกค่าไถ่ DeathRansom จะดำเนินการเข้ารหัสไฟล์ตามขั้นตอนดังนี้

  1. มัลแวร์นำกุญแจสาธารณะของผู้โจมตีมาผ่านฟังก์ชันเพื่อสร้าง object สำหรับการเข้ารหัสข้อมูลด้วยอัลกอริธึม RSA แบบ PKCS#1 OAEP
  2. สร้างสตริงซึ่งเก็บชื่อไฟล์ใหม่หลังจากที่ถูกเข้ารหัสแล้ว
  3. เปิดไฟล์ตามพาธที่ถูกส่งเข้ามา อ่านเนื้อหาในไฟล์ หลังจากนั้นใช้ object ซึ่งเกิดขึ้นจากการนำเข้ากุญแจสาธารณะมาทำการเข้ารหัสเนื้อหาไฟล์
  4. เปิดไฟล์เดิมใหม่อีกครั้ง แล้วเขียนข้อมูลที่ถูกเข้ารหัสแล้วทับลงไป
  5. เปลี่ยนชื่อไฟล์เป็นชื่อใหม่ตามที่ได้สร้างไว้ในขั้นตอนที่ 2

ถ้าเกิดข้อผิดพลาดใดๆ ในขั้นตอนเหล่านี้ กระบวนการเข้ารหัสไฟล์ในพาธดังกล่าวนี้จะไม่เกิดขึ้นทันที

Post-Infection

หลังจากกระบวนเข้ารหัสไฟล์เสร็จสิ้น มัลแวร์จะมีการสร้างไฟล์สคริปต์ไว้ที่พาธ %USERPROFILE%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\delete_ransom.bat ไฟล์ดังกล่าวจะมีจัดเก็บคำสั่งสำหรับการลบไฟล์โปรแกรมของมัลแวร์เอาไว้

หลังจากนั้นมัลแวร์จะทำการดาวโหลดโปรแกรมซึ่งจะทำการแสดง ransom note มาทำงานในระบบด้วยฟังก์ชัน download_ransomware_request

ท้ายที่สุดมัลแวร์จะทำการป้องกันไม่ให้ผู้ใช้สามารถเปิดใช้งานโปรแกรม Registry editor, Task manager และ Command prompt ได้ ก่อนจะบังคับให้ระบบทำรีสตาร์ทตัวเอง

Comments

  1. โครงการนี้ใช้ไลบรารีในการอิมพลีเมนต์อัลกอริธึมการเข้ารหัสและถอดรหัสซ้ำซ้อนกัน โดยมีการปรากฎของไลบรารีทั้ง Crypto และ pycryptodome ในไฟล์ requirements.txt ซึ่งสามารถเลือกใช้อย่างใดอย่างหนึ่งได้ อีกทั้งไม่มีการระบุโมดูล PyQt5 ในไฟล์ requirements.txt
  2. กระบวนการเข้ารหัสไม่จำเป็นต้องที่จะต้องมีการดาวโหลดกุญแจสาธารณะของผู้ควบคุมัลแวร์ก่อน เนื่องจากหากกระบวนการดาวโหลดไม่สำเร็จหรือถูกตรวจจับได้ก่อน มัลแวร์จะไม่สามารถทำง่นได้ มัลแวร์เรียกค่าไถ่อย่าง WannaCry ใช้วิธีการฝังค่ากุญแจสาธารณะของผู้โจมตีเข้าไปไว้ในโค้ดของมัลแวร์เลย
  3. โครงการไม่ได้รวมหน้าต่าง Ransom note ไว้ในโค้ดของมัลแวร์ทำให้มีขั้นตอนเพิ่มในการเตรียมการที่ไม่จำเป็นและไม่สมเหตุสมผล
  4. การตรวจสอบว่าโปรแกรมทำงานอยู่ใน sandbox หรือไม่ด้วยการตรวจสอบจากรายการโปรเซสเป็นวิธีการตรวจสอบที่ไม่สมบูรณ์ malware analyst สามารถเปลี่ยนชื่อของโปรแกรมซึ่งจะส่งผลให้ชื่อโปรเซสเปลี่ยนไปได้
  5. มีพาธของโค้ดซึ่งจะไม่ทำงานเนื่องจากโค้ดถูกบังคับให้จบการทำงานก่อน โดยเฉพาะอย่างยิ่งในส่วนของกระบวนการตรวจสอบหาความพยายามวิเคราะห์โปรแกรม
  6. การเข้ารหัสข้อมูลในไฟล์เพื่อเรียกค่าไถ่โดยการใช้ค่ากุญแจสาธารณะนั้นจะทำให้มัลแวร์ทำงานได้ช้าลง และหากคู่ของกุญแจสาธารณะถูกส่งมาเหยื่อเพื่อถอดรหัสไฟล์ เหยื่อจะสามารถทำการคัดลอกค่าดังกล่าวและแจกจ่ายไปยังเหยื่อคนอื่นๆ เพื่อให้สามารถถอดรหัสไฟล์ได้โดยที่ไม่ต้องจ่ายทันที