【技術分享】如何編寫有效的Yara特征
概述
筆者在去年夏天學習和分析CobaltStrike時編寫了一篇yara入門的文章,算是填坑,在此文中記錄下一些常見的編寫思路。
PDB路徑
PDB文件是在程序編譯時產生的,它記錄了程序的符號表,通過PDB,我們可以很方便對目標程序進行調試。
#程序編譯時分為Private Build和Public Build。#private build 表示開發人員在自己的電腦上進行coding和build,此時編譯后的程序和pdb在相同的路徑下。#Public build 表示開發人員在公用的電腦上進行build,在這種情況下,還需一個symbol server以存儲所有程序的pdb,當用戶程序報錯,debugger才能根據symbol server自動找到報錯程序所對應的pdb,加載符號以方便程序員進行調試
pdb信息一定是和生成的程序同名的,若生成的程序名為: normal.exe 那么對應的pdb一定為: normal.pdb。
當調試器加載目標進程的pdb時,調試器首先會嘗試查找與程序同名的pdb文件,若成功找到目標pdb,調試器則會檢查嵌入到PDB和目標進程中的GUID是否匹配,匹配則成功加載,不匹配則加載失敗。由于GUID計算時會使用時間因子,所以pdb和程序總是一一對應的。

還是以上面的簡單代碼為例,在加載pdb之后,可以最大程度的還原符號表,提升分析效率

了解了pdb的作用和基本原理之后,下面來看看在樣本查殺和hunting中pdb發揮的作用。
#需要稍微區分下hunting和查殺的區別#通常在樣本hunting時可以將特征寫的寬泛一些,因為hunting的目的是盡可能的根據當前的信息去尋找更多的樣本,在這種情況下,是允許誤報并且可以由特征編寫人員去人工判定誤報的。#而查殺,也就是惡意代碼查殺方向,對特征的要求會比較高,通常不能接受誤報,特征編寫人員需要把握好查殺率和誤報率之間的平衡。
一般來說,在分析中遇到的pdb信息有如下幾類
1、普通pdb名,可完全匹配pdb,以pdb信息作為查殺條件。
2、以pdb路徑中的部分信息作為過濾條件,快速過濾掉不相干樣本。
3、無字面意義pdb,如文件名稱為隨機字符串,此類pdb最好不好選做特征,否則將會變成單殺特征。
4、帶人名/盤符/路徑/日期/等信息的有價值pdb,此類pdb有可能是攻擊者不小心留下來的,價值較高。
5、誤導性pdb,有的pdb信息不僅無用,還會誤導分析人員。
普通pdb
以最近又異常活躍的Dridex為例,筆者在分析其中一個樣本時發現樣本中保留的pdb信息如下:

這里只是一個孤零零的pdb名稱,并無路徑信息,且此pdb名稱并無實際意義,在vt上對此信息進行檢索,能查到大批相關樣本(從文件大小可以看出這些樣本其實是相同的,可能只修改了極少的字節所以有了不同的md5,這里只是用它們舉一個簡單的例子)

關于Dridex相關的樣本,MalawareBazaar上面倒是又不少,這里剛好可以借助其進行練習。筆者之前根據bazaar提供的API接口寫了個簡單的腳本用于批量查詢樣本并獲取基本信息,效果如下

免費注冊bazaar之后將會得到一個APIkey,將自己的APIkey填充到下面的腳本中即可,調用方式為:
python3 get_bazaar_samples_info.py
比如要得到上面csv中的內容,輸入
python3 get_bazaar_samples_info.py Dridex 10
import sysimport requestsimport osimport jsonimport csvimport datetime
def getbaseinfo(tag,limit): getdate = datetime.datetime.now().strftime('%Y-%m-%d') csvFileName = getdate + "_" + tag + '.csv' f = open(csvFileName,'w',newline='',encoding='utf-8') csv_writer = csv.writer(f) csv_writer.writerow(['sha256_hash','md5_hash','first_seen','file_name','file_size','file_type','signature','tags','clamav'])
headers = {'API-KEY':'your API key'} data = { 'query':'get_taginfo', 'tag':''+tag+'', 'limit':''+limit+'' } response = requests.post('https://mb-api.abuse.ch/api/v1/', data=data,headers=headers) json_response = json.loads(response.content) samples_info = json_response['data'] for sample in samples_info: hash256 = sample['sha256_hash'] md5 = sample['md5_hash'] first_seen = sample['first_seen'] file_name = sample['file_name'] file_size = sample['file_size'] file_type = sample['file_type'] signature = sample['signature'] tags = sample['tags'] intelligence = sample['intelligence'] if 'clamav' in intelligence.keys(): clamav = intelligence['clamav'] else: clamav = "" csv_writer.writerow([hash256,md5,first_seen,file_name,file_size,file_type,signature,tags,clamav]) f.close() # print(json_response['data'][0]['md5_hash'])if __name__ == '__main__': if len(sys.argv) < 3: print("Usage: python3 get_bazaar_samples_info.py ") quit() tag = sys.argv[1] limit = sys.argv[2] getbaseinfo(tag,limit)
同樣的,也可以根據bazaar提供的API接口完善腳本,實現查詢之后自動從bazaar上下載樣本并解壓到本地。
樣本下載回來之后,按照大小排序,可以看到一共有三類樣本,分別是162kb大小、160kb大小和159kb大小。三類樣本對應的pdb信息分別是 Gsp.pdb、fffp4.pdb、Gsp.pdb

此時,光通過fffp4.pdb這個信息已經不足以匹配完我們視野范圍內的Dridex樣本了,這也是光以pdb信息作為特征點的一個局限性:通用性較差,很有可能查不了代碼沒怎么改變的變種樣本。
通過pdb過濾
上面樣本遇到的fffp4.pdb,通過google引擎檢索之后只有6條相關結果,且出來的結果都是沙箱相關的檢測報告,點進去發現對應的樣本的確是屬于Dridex的惡意樣本,因此可以考慮以fffp4.pdb作為一條特征。

但是更多的時候,我們可能在樣本中會遇到名字普普通通的pdb名稱,此時再用pdb作為特征就明顯不合適。以ebb83160e97ea11f46057a92f16e37ec樣本為例,該樣本所包含的pdb名稱為debug.pdb

debug.pdb這個名字較為常見,此時若是以該名字作為特征明顯不合適,但是這里可以注意到,一般情況下,正常程序的pdb信息是完整路徑,而不是像這個樣本中孤零零的一個文件名。所以正常程序的debug.pdb前面應該是路徑中的斜杠而不是00,因此可以加上00在vt上進行connect搜索:

搜索結果返回回來全是惡意程序,但這并不意味著可以直接以這段hex作為特征,我們將搜索結果限制在報毒數小于10可以看到就出現了一些白樣本

因此,此類pdb可以作為一個篩選過濾條件。
再來看看另一批樣本,原始樣本中的pdb信息如下

在只有一個樣本或是一批相同樣本的情況下比較難利用此pdb信息做文章,筆者在分析和關聯之后,定位到了同源,但是擁有不同pdb的樣本,信息如下

經過簡單的關聯分析之后,很快可以得到結論,該家族的樣本binIE\MiniIE2.pdb 的信息不會變,前面的盤符和code_路徑有可能改變,但若只匹配binIE\MiniIE2.pdb 還是有一定幾率的誤報,所以可以以該段hex數據作為過濾條件,加上部分的實際代碼抑制誤報。
無意義pdb
嚴格意義上來講,上面提到的fffp4.pdb也算是無意義pdb,因為將該pdb信息寫成yara特征,掃描回來的樣本必然是大同小異的,或者說代碼段幾乎完全相同,在這種情況下,看似是pdb信息起了作用,實際上隨便取一段代碼的opcode做特征效果也一樣。
還有一種筆者認為的無意義pdb是隨機字符串pdb,如下所示:

此類pdb沒有路徑等信息,基本上只會出現一次,就算通過該信息關聯到了樣本,情況和上面的fffp4.pdb也大致相同。
高價值pdb
“高價值”pdb信息通常出現在高級威脅追蹤與分析中。
以BITTER為例,部分樣本殘留了pdb信息:
C:\Users\ARAGON\Documents\Visual Studio 2008\Projects\DownWin32\Release\DownWin32.pdb
C:\Users\UserA\Documents\Visual Studio 2008\Projects\Artra\Release\Artra.pdb

雖然此類樣本pdb信息不相同,代碼也相差甚遠,但是pdb的命名風格卻較為相似。
C:\Users{UserName}\Documents\Visual Studio 2008\Projects{demoName}\Release{DemoName}.pdb
從上面兩個樣本來看,可變部分是上面橙色標記的幾個值,但是這里不妨猜測,Visual Studio的版本后面也會變,所以可以編寫一條正則特征,用于檢測包含了下面這種模式pdb的樣本
C:\Users{UserName}\Documents\Visual Studio {2008}\Projects{demoName}\Release{DemoName}.pdb
后面的樣本也能佐證這條特征的合理性:

繼續分析,還能看到有的樣本中加入了時間因子,這里的28Nov應該是表示11月28,我們可以對比分析作者信息不相同的樣本,慢慢找到BITTER中不同人員的分工,以及他們的共用代碼。

錯誤pdb
一個典型的錯誤pdb是msf框架所生成的meterpreter的payload。
#常見的msf馬有兩種#一類是patch入口點,創建線程執行shell code之后跳轉到原始的入口點繼續執行。#一類是將入口點完全替換為msf的shellcode,此類樣本會直接通過多個跳轉動態解密執行。
msf默認生成的meterpreter樣本尾部有一個pdb路徑叫做:C:\local0\asf\release\build-2.2.14\support\Release\ab.pdb

這里的pdb其實不是msf自身的pdb,而是Apache提供的性能檢測工具ab.exe的pdb信息。

patch ab.exe是msf的常見手法,通常來說,msf生成的meterpreter還會保留ab.exe的版本信息,筆者暫未閱讀過msf的源碼,所以猜測起初可能是為了增加樣本的免殺性,但是目前在免殺方面已經沒什么效果,可能可以迷惑一下初級的樣本分析人員

雖然這里的pdb路徑不在正常的位置的,IDA載入文件時也不會提醒加載pdb,但是yara作為全文掃的引擎,不能指定pdb出現的位置,為了避免誤報,所以不能取這樣的pdb作為特征。
關于PDB,暫時說這么多,總的來說,樣本中殘留的pdb信息有時可以比較好的幫助我們完成溯源、關聯等工作。但是不適合作為特征,可以在yara中作為一個可選條件。
互斥體
和pdb一樣,互斥體大多數時候并不能直接作為查殺特征甚至是hunting特征,只是在深入分析某個組織,構建TTPS時可以起到一定的作用。
大多數惡意軟件感染計算機之后會通過計劃任務、開機啟動注冊表、啟動項等方式實現本地持久化,但是像計劃任務啟動這種方式有可能會倒是程序多開,過多的進程名可能會引起用戶或運維人員的注意,為了避免此類情況,攻擊者有時候會創建互斥體以保證樣本在主機上只有一個實例運行。
惡意軟件常見的互斥體有以下幾類
1、獲取當前的計算機基本信息計算出一個ID,以該ID作為互斥體名
2、硬編碼在代碼中的互斥體名,如程序名、C2地址、地名、小說人物名、隨機亂碼名
3、仿冒正常程序的互斥體名。
互斥體取名相對來說比較”困難”,為了避免不同版本的惡意軟件感染同一個主機并在主機上同時運行,攻擊者通常需要選用多個版本同時適用的互斥體名。
比較直接的做法是獲取用戶主機的計算機名、用戶名等信息通過固定的算法生成一個ID用于標識受害者主機,這個ID可以作為互斥體名,同時也可以作為請求頭中的id,發送上線標識包。
還有一個簡單的做法是以請求域名作為互斥體名稱,這樣可以保證,與同一個C2通信的樣本不會重復運行。
不過大部分的惡意軟件開發者會選擇實用隨機字符串作為互斥體名,這可能是他們沒有考慮版本更新方面的問題,也有可能是有意為之。
隨機字符串
以Clop勒索軟件為例(7edc821c3b46e85f262a96182ed2de86),樣本運行后會在線程中創建名為
FSKJHFOJKW#^^^66^6
的互斥體,經過搜索引擎和VT可得知該互斥體名為隨機生成,并無實際意義,所以不能作為樣本特征。

以Clipper家族的樣本為例,同一批樣本,代碼結構很相似,但是創建的互斥體名也是不同的,這里的互斥體名也是通過隨機字符生成,不能作為特征點或是關聯分析的關鍵點。

請求域名
以05690a450fea902744c9f7560a999267樣本為例,樣本運行后,會創建名為
qq2009.3322.org
的互斥體名

通過VT也可以看到,的確有很多樣本請求了該域名

因此,類似于這種以域名作為互斥體名的樣本,是可以考慮直接以互斥體名(域名)作為特征的,但是這個特征說是查互斥體名,其實也是查域名,通用性相對來說也較差。
偽裝
在上面講pdb的時候講到了有的惡意軟件會偽裝正常軟件的pdb信息以迷惑用戶,互斥體也不例外。
以e6fcdc19924db03a6c2c026c7992344b樣本為例,樣本運行后會創建名為chromiumUndate的互斥體名。

這里的互斥體名很明顯是仿冒了Chromium更新程序名,此外,攻擊者還仿冒了Chromium的版本信息

并且特意保留了仿冒Chromium的pdb信息,希望通過這三層信息迷惑用戶或是迷惑初級分析人員

此類樣本的特征是相對危險的,在提取時需要格外注意。
計算生成
通過收集本地主機信息計算ID作為互斥體名的一般是高級威脅所涉及的樣本。
這里又會分為兩類
1、 直接在樣本中獲取指定信息,計算,然后生成互斥體名。
2、 上一階段的樣本獲取信息并計算ID傳入到C2,C2根據此ID生成對應的樣本。
通過這種方式,較難根據互斥體名進行溯源或是主動關聯其他樣本,但是我們可以收集和記錄,在遇到該家族其他樣本時進行被動關聯。
關于此類互斥體名,已經脫離了靜態特征的范疇,在此節中不進行深入討論