python_mmdt:ssdeep、tlsh、vhash、mmdthash对比
2022-3-5 17:57:0 Author: mp.weixin.qq.com(查看原文) 阅读量:113 收藏


本文为看雪论坛优秀文章
看雪论坛作者ID:大大薇薇

前文回顾

python_mmdt:一种基于敏感哈希生成特征向量的python库(一)

(https://bbs.pediy.com/thread-265211.htm)

我们介绍了一种叫mmdthash(敏感哈希)生成方法,并对其中的概念做了基本介绍。

python_mmdt:从0到1--实现简单恶意代码分类器(二)

(https://bbs.pediy.com/thread-265499.htm)

我们介绍了基于mmdthash的一种简单恶意代码分类器应用。

python_mmdt:从1到2--实现基于KNN的机器学习恶意代码分类器(三)

(https://bbs.pediy.com/thread-265860.htm)

我们介绍基于mmdthash的机器学习恶意代码分类器应用。

python_mmdt:mmdthash的在线使用(四)

(https://bbs.pediy.com/thread-271243.htm)

我们介绍如何使用mmdthash实现在线恶意文件检测。

python_mmdt:KNN机器学习分类结果测试分析(五)

(https://bbs.pediy.com/thread-271265.htm)

我们对基于KNN机器学习算法的分类结果进行统计测试,评估分类模型。

本篇,我们对ssdeep、tlsh、vhash、mmdthash这四类敏感哈希算法效果进行对比。

项目地址

github代码地址:python_mmdt(https://github.com/a232319779/python_mmdt)

对比结论

准确率ACC:tlsh > mmdthash > ssdeep > vhash

召回率REC:tlsh > mmdthash > ssdeep > vhash

精确率PRE:mmdthash = ssdeep = vhash > tlsh

基于本篇的测试结果,在mmdthash阈值取0.95,ssdeep阈值取0.8,tlsh阈值取0.8的前提下,敏感哈希效果的综合排序如下:
 
tlsh > mmdthash > ssdeep > vhash

敏感哈希介绍

四类敏感哈希一览:
CTPH(ssdeep)(https://ssdeep-project.github.io/ssdeep/index.html):
Context Triggered Piecewise Hashes(CTPH),又叫模糊哈希,最早由Jesse Kornblum博士在2006年提出,论文地址(https://ssdeep-project.github.io/ssdeep/index.html)。CTPH可用于文件/数据的同源性判定。据官方文档介绍,其计算速度是tlsh的两倍(测试了一下,好像并没有)。
tlsh(https://tlsh.org/index.html):
是趋势科技开源的一款模糊哈希计算工具,将50字节以上的数据计算生成一个哈希值,通过计算哈希值之间的相似度,从而得到原始文件之间的同源性关联。据官方文档介绍,tlsh比ssdeep和sdhash等其他模糊哈希算法更难攻击和绕过。
vhash(https://developers.virustotal.com/reference/files):
(翻遍了整个virustotal的文档,就找到这么一句话)“an in-house similarity clustering algorithm value, based on a simple structural feature hash allows you to find similar files”,大概就是说是个内部相似性聚类算法,允许你通过这个简单的值,找到相似的样本。
mmdthash(https://github.com/a232319779/python_mmdt):
是开源的一款模糊哈希计算工具,将任意数据计算生成一个模糊哈希值,通过计算模糊哈希值之间的相似度,从而判断两个数据之间的关联性。详情前文1-5篇。

对比思路

基于python_mmdt:KNN机器学习分类结果测试分析(五)文章中的mmdthash测试数据及测试结果,对ssdeep、tlsh、vhash进行对比测试。即计算mmdthash关联出的两个样本之间的ssdeep、tlsh、vhash相似度,并统计分析相关的异常值、精确度、召回率、精确率,从而得出敏感哈希算法之间的对比结果。

对比过程

说明:ssdeep和tlsh在Windows上的安装比较折腾,测试直接在树莓派的Linux环境上进行。

1. ssdeep计算

ssdeep安装:
安装模糊哈希库:sudo apt-get -y install libfuzzy-dev ssdeep
安装ssdeep的python库:pip install ssdeep
或者,如果linux的编译环境比较全(包含automake等工具),可以直接通过pip安装ssdeep的模糊哈希库:BUILD_LIB=1 pip install ssdeep
 
利用python的ssdeep库计算785个测试文件的ssdeep值,并使用json格式保存在文件中,代码如下:
# -*- coding: utf-8 -*-
import osimport sysimport hashlibimport jsonimport ssdeep
# 遍历目录def list_dir(root_dir): files = os.listdir(root_dir) for f in files: file_path = os.path.join(root_dir, f) yield file_path
# 生成sha1def gen_sha1(file_name): with open(file_name, 'rb') as f: s = f.read() _s = hashlib.sha1() _s.update(s) return _s.hexdigest()
def main(): # 输入785个文件的路径 file_path = sys.argv[1] ssdeep_dict = dict() for file_name in list_dir(file_path): file_sha1 = gen_sha1(file_name) ssdeep_hash = ssdeep.hash_from_file(file_name) print('%s,%s' % (file_sha1, ssdeep_hash)) ssdeep_dict[file_sha1] = ssdeep_hash # 使用json文件保存结果 with open('ssdeep_test.json', 'w') as f: f.write(json.dumps(ssdeep_dict, indent=4))

if __name__ == '__main__': main()
ssdeep计算结果示例如下:
cat ssdeep_test.json{    "0ec279513e9e8a0e8f6e7c170b9462b60d9888c6": "6144:w9qaZ5E6fCvH5H42SUiTV2MTb54y94HTFboTWhmzeOws:w9d96yeKV2MTb5X4zZQWhmqd",    "0ad6db9128353742b3d4c8a5fc1993ca8bf399f1": "1536:NxiIXeGNc0BL0IFx34bPMkG/KsrKlEqjjPWUJ7h/dbZkv13t43O:eIXeGNtV0KIQjr5ehlbSv13t43O",    "e3dc592a0fa552beb35ebcb4160e5e4cb4686f17": "1536:qKXppRU0D2KmMESllkQSp5jcUyT/jAdp/hsonBqar5mVNCG:JpGjKm9fQSp5sjAfAa1mVMG",    "c8e1100b1e38e5c5e671a23cd49d98e315b74a36": "3072:XwZcFNCpegr+L3Y5D+LRohyOBGbNc8GMmE/A9VpGLGWtQeGwX1gnuZPZc2:XHCNEY5D+LfOi3GbE/AsAeGwXwc5",    "0ae0cba5b411541cc8d9f94e01151fec9d6b9242": "384:enXKs1aOcWkZ1WgoELXuf9OO5GD+IGA4p1XMWfg7CF:enp1aOasDOOM+ut",    ......}

2. tlsh计算

tlsh安装:pip install py-tlsh
 
利用python的tlsh库计算785个测试文件的tlsh值,并使用json格式保存在文件中,代码如下:
# -*- coding: utf-8 -*-import osimport sysimport hashlibimport jsonimport tlsh
# 遍历目录def list_dir(root_dir): files = os.listdir(root_dir) for f in files: file_path = os.path.join(root_dir, f) yield file_path
# 生成sha1def gen_sha1(file_name): with open(file_name, 'rb') as f: s = f.read() _s = hashlib.sha1() _s.update(s) return _s.hexdigest()
def gen_tlsh(file_name): with open(file_name, 'rb') as f: s = f.read() _s = tlsh.hash(s) return _s

def main(): # 输入785个文件的路径 file_path = sys.argv[1] tlsh_dict = dict() for file_name in list_dir(file_path): file_sha1 = gen_sha1(file_name) tlsh_hash = gen_tlsh(file_name) print('%s,%s' % (file_sha1, tlsh_hash)) tlsh_dict[file_sha1] = tlsh_hash with open('tlsh_test.json', 'w') as f: f.write(json.dumps(tlsh_dict, indent=4))

if __name__ == '__main__': main()
tlsh计算结果示例如下:
cat tlsh_test.json{    "0ec279513e9e8a0e8f6e7c170b9462b60d9888c6": "T1616423D5248C5DF8E251CCF4C73AB60493EADA48BF516B75BDD9C2692FF2480C93A214",    "0ad6db9128353742b3d4c8a5fc1993ca8bf399f1": "T13D73024483EBEDA8EE040AB0124C43B9CBAD8D1B7659653DFD3864D1FC064AE47269A6",    "e3dc592a0fa552beb35ebcb4160e5e4cb4686f17": "T1CF93293D766924E5E139C17CC5474E0AF772B025071227EF06A4C2BE1F97BE06C39AA5",    "c8e1100b1e38e5c5e671a23cd49d98e315b74a36": "T17F34391A57EC0465F1B7923589B34919F233B8625731E2DF109082BC2E27FD8BE36B56",    "0ae0cba5b411541cc8d9f94e01151fec9d6b9242": "T12D5208C71F69F7D4C19F85F84A3B623E1EA4616A6111412057DD3E92BC1C3DBFA2A09C",    ......}

3. vhash计算

virustotal没有开源vhash的计算方法,目前只能通过virustotal的web api接口进行查询。通过virustotal的接口,同时可以获取到对应文件的ssdeep和tlsh值(估计tlsh上virustotal的时间比较短,一些老样本会缺失tlsh值)。virustotal的api文档(https://developers.virustotal.com/reference/file-info),可以直接在页面上对接口进行测试以及生成对应开发语言的代码,使用非常方便。
 
注册virustotal的账户,申请api_key请参考virustotal的文档,几分钟即可完成。使用api接口进行查询的时候,注意查询频率限制。
 
使用python查询virustotal的代码如下:
# -*- coding: utf-8 -*-
import sysimport jsonimport requestsfrom time import sleep
# virustotal api keyx_apikey = 'xxxx'
def read_hash(file_name): with open(file_name, 'r') as f: datas = f.readlines() return [file_hash.strip() for file_hash in datas]
def parse_vt_report(vt_report_json): attributes = vt_report_json.get('data', {}).get('attributes', {}) parse_data = dict() if attributes: # 同时记录文件的ssdeep/tlsh/vhash/文件类型 parse_data['vhash'] = attributes.get('vhash', '') parse_data['magic'] = attributes.get('magic', '') parse_data['tlsh'] = attributes.get('tlsh', '') parse_data['ssdeep'] = attributes.get('ssdeep', '')
return parse_data
def vt_search(sha1_hash): url = "https://www.virustotal.com/api/v3/files/{}".format(sha1_hash)
headers = { "Accept": "application/json", "x-apikey": x_apikey }
response = requests.request("GET", url, headers=headers) try: parse_data = parse_vt_report(response.json()) except Exception as e: print('error: %s, reason: %s' % (sha1_hash, str(e))) return parse_data
def main(): # 包含待查询哈希的文件路径 file_path = sys.argv[1] vhash_dict = dict() file_hashs = read_hash(file_path) for file_hash in file_hashs: parse_data = vt_search(file_hash) print('%s,%s' % (file_hash, json.dumps(parse_data))) if parse_data: vhash_dict[file_hash] = parse_data else: break sleep(1) with open('vhash_test.json', 'w') as f: f.write(json.dumps(vhash_dict, indent=4))

if __name__ == '__main__': main()
vhash查询结果如下:
cat vhash_test.json{    "aba1301af627506cf67fd61410800b37c973dcb6": {        "vhash": "1240451d05151\"z",        "magic": "PE32+ executable for MS Windows (DLL) (console)",        "tlsh": "T151B22A828BB81403FA767D7013A8D6837D3D67D60820856915AAF5AA2C833C5EF10F7E",        "ssdeep": "192:8fPNlWZYWfUyfUlHDBQABJB3ejpC52qnaj68tj:iNlWZYW+DBRJ4Nle8tj"    },    "5f3ebf2c443f7010d3a5c2e5fa77c62b03ca1279": {        "vhash": "1240451d05151\"z",        "magic": "PE32+ executable for MS Windows (DLL) (console)",        "tlsh": "T140B239D6CBBC0547E9663EB012A8E9873D3E73EB4820416905A5F1981C837C5EF00F6E",        "ssdeep": "192:8Ih6WxwWFUyfUlHDBQABJj1N80Hy5qnajWi8sA+F:Vh6WxwW0DBRJjPsl+yF"    },    "3d57ce2f5149f1d9609608bc732d86637fe20cce": {        "vhash": "1240451d05151\"z",        "magic": "PE32+ executable for MS Windows (DLL) (console)",        "tlsh": "T18FB23AC2CBEC5443EAA67A7043A8E58B7D3DB3D21C60855904A6E1591CD33C2EF24E7E",        "ssdeep": "192:8JWhOMrlWBwWYUyfUlHDBQABJ5cWvKxEHsqnajTT0f7:kWhOMRWBwWhDBRJNKxUsl3TM"    },    ......}

4. mmdthash计算

使用python_mmdt:KNN机器学习分类结果测试分析(五))中的测试结果。

结果对比

1. ssdeep、tlsh、vhash、mmdthash结果整合

将上述计算过程生成的ssdeep_test.json、tlsh_test.json、vhash_test.json、mmdthash_test.json文件中的数据,按字典形式,整合至ssdeep_tlsh_vhash_mmdthash_test.json文件中,示例如下:
{    "aba1301af627506cf67fd61410800b37c973dcb6": {        "vhash": "1240451d05151\"z",        "magic": "PE32+ executable for MS Windows (DLL) (console)",        "tlsh": "T151B22A828BB81403FA767D7013A8D6837D3D67D60820856915AAF5AA2C833C5EF10F7E",        "ssdeep": "192:8fPNlWZYWfUyfUlHDBQABJB3ejpC52qnaj68tj:iNlWZYW+DBRJ4Nle8tj",        "mmdthash": "07022B59:7202890402200212DA032EC310AFEF8A"    },    "5f3ebf2c443f7010d3a5c2e5fa77c62b03ca1279": {        "vhash": "1240451d05151\"z",        "magic": "PE32+ executable for MS Windows (DLL) (console)",        "tlsh": "T140B239D6CBBC0547E9663EB012A8E9873D3E73EB4820416905A5F1981C837C5EF00F6E",        "ssdeep": "192:8Ih6WxwWFUyfUlHDBQABJj1N80Hy5qnajWi8sA+F:Vh6WxwW0DBRJjPsl+yF",        "mmdthash": "07022B59:7102870402200212DD032DC30EA0F1A9"    },    ......}

2. 敏感哈希相似度计算

使用python_mmdt:KNN机器学习分类结果测试分析(五))中的mmdthash分类结果作为依据,计算关联文件之间的ssdeep、tlsh、vhash的相似度值。计算过程有3点需要注意:
① ssdeep的计算结果是[0,100]之间的相似值,0表示完全不相关,100表示基本完全一致。为方便对比计算,本测试中,对ssdeep的相似值做归一化处理,即转为[0,1]之间的相似度值,转化方法:相似度 = 相似值/100.0
② tlsh的计算结果是[0,X]之间的距离值,0表示基本完全一致,X的上限暂时不清楚,但距离越大,表示文件差异越大。为方便对比计算,本测试中,对tlsh的值做归一化处理,即转为[0,1]之间的相似度值,转化方法:相似度 = 1.0 - 距离值/1160.0(1160.0取400个测试数据中的最大值)
③ vhash的相似度计算方法未公开,暂时仅取两个值,0和1,0表示两个vhash不相等,1表示两个vhash相等
对比计算代码如下:
# -*- coding: utf-8 -*-import jsonimport ssdeepimport tlsh
def read_hash(file_name): with open(file_name, 'r') as f: datas = f.readlines() return [file_hash.strip() for file_hash in datas]
def ssdeep_compare(data1, data2): h1 = data1.get('ssdeep', '') h2 = data2.get('ssdeep', '') score = ssdeep.compare(h1, h2)
return score/100.0
def tlsh_compare(data1, data2): h1 = data1.get('tlsh', '') h2 = data2.get('tlsh', '') score = tlsh.diff(h1, h2)
return 1 - score/1160.0
def vhash_compare(data1, data2): h1 = data1.get('tlsh', '') h2 = data2.get('tlsh', '') score = 1.0 if h1 == h2 else 0.0
return score
def main(): mmdt_hash_sim = read_hash('./mmdt_sim.csv') with open('./ssdeep_tlsh_vhash_mmdthash_test.json', 'r') as f: vhash_json = json.loads(f.read()) print('原始文件,相似文件,mmdt相似度,ssdeep相似度,tlsh相似度,vhash相似度,原始文件类型,相似文件类型') for mhs in mmdt_hash_sim: tmp = mhs.split(',') ori_hash = tmp[0] sim_hash = tmp[1] mmdt_sim = float(tmp[2]) ori_data = vhash_json[ori_hash] sim_data = vhash_json[sim_hash] ssdeep_sim = ssdeep_compare(ori_data, sim_data) tlsh_sim = tlsh_compare(ori_data, sim_data) vhash_sim = vhash_compare(ori_data, sim_data) ori_type = ori_data.get('magic', '').split(' ')[0] sim_type = sim_data.get('magic', '').split(' ')[0] print('%s,%s,%.3f,%.3f,%.3f,%.3f,%s,%s' % ( ori_hash,sim_hash,mmdt_sim,ssdeep_sim,tlsh_sim,vhash_sim,ori_type,sim_type ))
if __name__ == '__main__': main()
涉及的相关文件及下载地址:
① 整合后的完整测试数据文件ssdeep_tlsh_vhash_mmdthash_test.json下载地址:https://bbs.pediy.com/upload/attach/202201/467421_PP739ABEBEEEDUW._json
② mmdthash分类结果文件mmdt_sim.csv
下载地址:https://bbs.pediy.com/upload/attach/202201/467421_JKYV8K9RE55G4V4._csv
③ 结果文件ssdeep_tlsh_vhash_mmdthash_test.xlsx
下载地址:https://bbs.pediy.com/upload/attach/202201/467421_WTPBRUEPET5Q2MV.xlsx
ssdeep_tlsh_vhash_mmdthash_test.xlsx示例数据如下:

3. 结果分析

如前文所述,我们使用mmdthash的检出结果作为基线,对ssdeep、tlsh、vhash的结果进行对比。
 
mmdthash检出结果对比
 
mmdthash相似度阈值取0.95,相似度按从大到小排序,前133个文件是检出为恶意的文件,其中132个检测正确,为恶意文件,最后一个检测错误,恶意家族检测分类结果不一致。
 
mmdthash未检出结果对比
 
mmdthash相似度阈值取0.95,相似度按从大到小排序,后267个文件为未检出的文件,其中有200个检测正确,为干净文件,有67个检测错误,将恶意文件预测为干净文件。
 
对比
结合两张相似度分布图,ssdeep取0.8作为判定阈值:
133个检出样本中,ssdeep检出109个,未检出24个
267个未检出样本中,ssdeep检出5个,未检出262个
同上,tlsh取0.8作为判定阈值:
133个检出样本中,tlsh检出131个,未检出2个
267个未检出样本中,tlsh检出22个,未检出245个
同上,vhash由于取值只有0和1,所以:
133个检出样本中,vhash检出5个,未检出128个
267个未检出样本中,tlsh检出0个,未检出267个
通过人工分析异常点对应的样本,mmdthash阈值取0.95,ssdeep阈值取0.8,tlsh阈值取0.8,得到统计数据如下:
如图所示:
 
在上述mmdthash阈值取0.95,ssdeep阈值取0.8,tlsh阈值取0.8的前提下,可得出如下结论:

tlsh的准确率、召回率、误报率最高(误报率 = 1.0 - 准确率)

mmdthash的准确率和召回率次之,准确率比tlsh低1.5%,召回率比tlsh低9.0%,误报率比tlsh低5.5%

ssdeep的准确率和召回率再次之,准确率比tlsh低6.8%,召回率比tlsh低21.4%,误报率比tlsh低5.5%

vhash情况最特殊,数据做观察对比即可

综上,基于本篇的测试结果,敏感哈希效果的综合考虑如下:
tlsh > mmdthash > ssdeep > vhash

其他

1. 400个测试文件类型分布

PE文件占比96%

ELF文件占比2%

其他文件占比2%

2. 400个测试文件计算耗时

为体现差异,特意在低性能的树莓派上执行,耗时如下:

反思与收获

① ssdeep的论文写的真不错,通俗易懂,论证过程清晰,数学理论支撑非常充足,非常棒。

② tlsh的生态做的真的好,已经出了6篇相关的paper,参与了6次会议,足以证明其应用效果。

③ 在实现mmdthash的过程中,过于闭门造车,有很多不成熟的想法、思路在tlsh相关的paper里都讲述的很清楚、很详细,应用也非常成熟了。

④ mmdthash的性能还要持续优化。

 

看雪ID:大大薇薇

https://bbs.pediy.com/user-home-467421.htm

*本文由看雪论坛 大大薇薇 原创,转载请注明来自看雪社区

# 往期推荐

1.malloc源码分析

2.Windows本地代码执行漏洞(CVE-2012-1876)x86/x64平台分析

3.栈溢出原理与实践之读书笔记

4.符号执行挖掘开源库命令注入

5.CVE-2021-4034 pkexec本地提权漏洞复现与原理分析

6.侠盗猎车—玩转滚动码

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458431877&idx=2&sn=a988b205401c3e39ef029f0be5f99c1d&chksm=b18f810f86f808190d2ebc06b0ca03040b9518791c9cd93de7a7456d6eebee0c0c5be9edab80#rd
如有侵权请联系:admin#unsafe.sh