2019年9月20日 星期五

勒索病毒

勒索病毒是近幾年來興起的一種病毒,發作時會將電腦某些檔案加密,其特徵是原本檔名後會加上類似 ID、email 和自創的副檔名,該病毒程式便可以知道那些是加密過的檔案避免再 2 次加密,在 C 槽和 D 槽或是被加密的資料夾中,會留下一個文字檔,提醒中了勒索軟體,裡面並指定要用比特弊交易,甚至是教導如何購買比特幣XD

根據本人猜測,病毒程式應該是在發作時,先將本機電腦相關資訊送回伺服器產生 ID,並取回非對稱加密演算法的公鑰,之後便利用這把 Key 開始工作。

根據觀察某中毒電腦,病毒應該是同時開啟幾個 thread 對不同槽加密,故我在 C 槽和 D 槽看到不同的檔案卻有著同樣的最後修改時間。

底下是某中毒電腦 D 槽被加密的檔案個數及加密花費時間資訊

178,787 個檔案,花費 6 個小時又 43 分。


不靠病毒軟體監控辦法﹝很容易被反制,但聊剩於無﹞

在各磁碟機根目錄放置一個不會被修改的假檔案,並在某磁碟機一個很深層的資料夾中放置一個程式去監控假檔案的最後修改時間,可以使用 polling 或是各作業系統的 event 通知機制來監控,只要發現異常就馬上執行關機動作,之後再用 Linux 開機碟開機來救援未被加密的檔案。

此原理是利用作業系統的檔案 API 機制,不管我們是使用什麼程式語言,當我們寫程式在 parsing 某資料夾檔案時,底層一定是呼叫到 OS API,理論上吐回來的 handle 應該都是照英文字母排序,故可以達到提早發現的效果。

底下為使用 Go 寫的 sample code

package main

import (
    "fmt"
    "os"
    "os/exec"
    "time"
)

func SomethingWrong() bool {
    var t int64 = 1568963531

    files := []string{
        "C:\\0\\000000.txt",
        "D:\\0\\000000.txt",
        "E:\\0\\000000.txt",
    }

    for _, name := range files {
        fileinfo, err := os.Stat(name)
        if err != nil {
            fmt.Printf("File (%s) is gone. \r\n", name)
            return true
        }

        atime := fileinfo.ModTime()
        //fmt.Println(name, atime, atime.Unix())

        if atime.Unix() > t {
            fmt.Printf("Error : %v (%v) \r\n", name, atime)
            return true
        }
    }

    return false
}

func notifyMessage() {
    cmd := exec.Command("notepad", "電腦中毒了")
    cmd.Run()
}

func main() {
    ticker := time.NewTicker(time.Second * 2)
    defer ticker.Stop()

    isStop := false

    for {
        select {
        case _ = <-ticker.C:
            if SomethingWrong() {
                // do something
                notifyMessage()
                isStop = true
            }
        }

        if isStop {
            break
        }
    }
}

沒有留言:

張貼留言