0x01 种子寻找记之DGA算法分析
题目描述
本题中,选手需从给定的DGA样本中通过逆向分析发现其中存在的DGA算法。通过对DGA算法的分析,根据给出的同算法但不同种子生产的域名获得新的种子,最终给出使用新种子生产的所有域名。
题目分析
题目给出了三个样本以及三个域名列表,其中每个列表对应一个样本。三个样本的MD5是:68C2D387AA16EAD4575E02DAC2EAEDCC、2F2A766A3F5749D916111970C2A6F145、E90554A0EFB6E0A35FC611A7B7B727C0。首先,需要对三个样本进行逆向分析,可以不还原成源代码,但是需要知道域名的生成方式以及种子的格式。然后,对三个域名列表分析,找出生成这三个域名列表的DGA种子
解题过程
这一题的三个样本都没有做任何加壳和混淆处理,逆向分析相对较为容易。因此,接下来的分析过程不会讲如何进行样本逆向分析。
sample1.exe
此样本DGA种子有四个参数组成,前三个参数是年月日,第四个参数是一个整数。根据题目提示可知,前三个参数分别是2020,5,10。因此只需计算最后一个参数即可。
第一个列表给出的域名是按照算法生成的顺序的,因此只需用第一个样本暴力计算第四个参数即可。最终计算出种子是0x6D7D4AEB。
sample2.exe
此样本DGA种子是一个字符串和一个域名。在生成域名的时候,上一次生成的域名又作为下一次生成域名时的种子。因此,我们只需拿题目给出的域名列表中第一个域名作为DGA算法的第二个参数。
对于第一个字符串参数,如果暴力搜索整个字符串空间,那么这个搜索空间是非常大的。进一步分析域名生成算法可知,在生成域名的时候,实际上并没有直接使用这个字符串,而是先计算字符串ASCII码之后,然后保留最低位的数;接着再计算最后一个字节的ASCII码值。也就是说,根据这个字符串计算两个8位的数,只需计算这两个8位的数就可以,所以整个搜索空间实际上是 256*256=65536 ,这个搜索空间是可以很快就查找完的。最终计算出来这两个数分别是84和119。
sample3.exe
此样本的DGA种子是一个32位的整数,并且,题目所给的域名列表并不是顺序的,而是乱序的。因此,如果尝试暴力搜索种子,则需要对每一个可能的种子生成全部的1000个域名,然后判断这1000个域名和题目给出的100个域名有多少重复的,这样搜索带来的时间开销是无法接受的,需要使用成千上万台服务器才有可能再比赛结束之前找到。因此,需要寻找一种巧妙的方法寻找种子
我们的方法如下确定一个域名在原始1000个域名中的位置随机选择一个域名,假设该域名处于位置 i暴力寻找生成当前域名rand函数[1]的梅森随机数种子根据计算出来的梅森随机数种子,生成从 i 到 1000的所有域名如果假设的位置 i 是正确的,则上一步生成的域名列表 和 题目中给出的域名列表 会有部分重复的重复以上四步,直到找到真正的 i
重复前面计算,找到一个稍微靠前的域名13mrjyvjjp4azbbkt7.com 位置是722tojrtinlfkhwy777q4.biz 位置是 255
经过观察发现,rand函数操作是以19次为一个单元的,因此我们在内存中建立一个rand函数的映射表(此表约需要16GB的内存空间),保存rand函数和其梅森随机数种子的映射关系,这样就可以实现rand函数逆运算。有了这张映射表,就可以很快计算中正确的种子 0x04A5E1CC
0x02 逆水行舟之DGA逆向分析 - 阶段1
题目描述
找出包含在给定域名列表中的100个DGA域名
题目分析
DGA域名有以下特点:
DGA算法生成的域名只有一部分会被注册用于通信,还有一部分不被使用。这部分不被使用的DGA域名没有被注册过,也不存在解析记录。被注册的DGA域名也会有很少的解析记录。
基于算数的DGA算法是最常见的DGA算法,其特征是生成的域名看起来都是随机的字符串。
解题过程如下:
基于威胁情报的过滤过滤Alexa top 1M中的域名,这部分域名都是良性的域名
过滤到子域名过多的域名。DGA域名一般不会存在子域名。这里设置的阈值是3,当子域名数量大于或等于3的时候,就被过滤掉。过滤掉存在过多解析记录的域名。DGA域名一般只会使用短暂的一段时间,因此不会存在大量的解析记录。这里设置的阈值同样是3,当域名的解析记录大于或等于3的时候,就会被过滤掉。
以上三步可以过滤80%~90%的域名
基于分词的过滤(DGA的随机性)
对域名进行英文单词的分词,若域名中含有长单词,则过滤此域名。
对域名进行汉语拼音的分词,若域名中含有拼音,则过滤此域名。
经过检查点测试发现,三个域名中都不存在基于字典的DGA,因此以上两步的过滤是没问题的。
人工筛选
经过上面两步过滤,剩余的域名只有100-200个,是可以进行人工筛选的。
基于熵值的排序
由于DGA域名随机性强,域名的熵值就会相对更大,因此按照熵值排序,取熵值最大的前100个域名。
存在的问题
基于字典的分词过于简单,没有考虑单词(或拼音)之间的语义性
这种方法无法处理拼音首字母缩写的域名,如 hbjsjgyxgs.com 是一个正常的域名,是河北金属加工有限公司的首字母缩写。
针对这种情况,可以从拼音组成的角度来考虑。对于绝大部分拼音来说,都是由声母和韵母组成。而拼音的首字母缩写全部都是由声母组成(忽略那些没有声母的拼音),因此可以认为这种域名全部由声母组成。对中文常用词分析,利用隐马尔可夫模型计算不同拼音首字母在中文词语中的转换概率。
0x03 逆水行舟之DGA逆向分析 - 阶段2
题目描述
根据给出的样本,用python写出源代码。
题目分析
这一题相当于第一题的加强版,要求写出可执行的源代。并且,这题给出的三个样本比第一题的样本更为复杂,加入了一定程度的混淆操作。
解题过程
sample1.exe
第一个样本并没有做混淆处理,并且也很容易就可以修改成python代码
sample2.exe
第二个样本稍微复杂一些。样本动态解密并加载DLL文件,真正DGA部分是在这个DLL文件里面。需要dump出这个DLL文件,然后分析这个DLL文件就可以获得DGA部分代码。
我们分析发现,这个样本存在数组越界读的情况。越界读造成的后果是,每次生成域名的时候,最后几位是不一样的。发现这个问题之后,我们第一个时间向比赛组织方反应。经他们确认,这个问题是由于出题人的疏忽造成的。
具体的情况如下图,代码中实际申请了13*4个字节的空间。由于是在函数内部申请的,这部分内存是位于栈上面的。而实际上代码在使用的时候,使用了20*4个字节的空间。越界读取的8*4个字节是在函数调用的时候压入栈中的数据,分别是:4字节的security cookie、4字节的ebp、4字节的函数返回地址、4字节的参数1、4字节的参数2、4字节的esi、4字节的edi。由于每次执行前13*4个字节中的数据都是一样的,因此生成的域名前面部分是一致的;而域名的后面几位依赖越界读取的那些数据,所以每次生成的都不一样。
sample3.exe
这个样本中加入了大量的混淆和反调试,但只要patch jmp指令,直接跳转到有意义的部分即可。
下图这部分是真正有用的部分,这个函数的作用是:解密数据段中的dll文件,将该dll文件注入explorer.exe。详细的做法是:
在explorer.exe进程申请内存
写入解密后的dll文件
写入一段用于加载dll的shellcode
写入shellcode的参数
创建远程线程执行shellcode
直接dump出dll文件,就可以获得DGA部分代码。
0x04 恶意域名家族之全员通缉
题目描述
对给出域名的流量数据进行分析,按照请求特征对域名进行分类。
有标签的域名只占所有恶意域名的50%,请选手找出另外那50%的恶意域名并正确分类;
域名数量: 总量约20000个,其中恶意域名约1000个。
题目分析
题目给了6个数据文件和一个标签文件,分析后可以发现:标签只注明了0-8共9种恶意家族标签,但是没有给出良性样本标签,只有一类样本标签,无法直接应用监督学习模型训练;
存在样本数据缺失的情况,完整的样本数据只有fqdn.csv文件,即域名数据,其余文件都存在不同程度的数据缺失情况。
针对没有良性样本标签,只有恶意样本标签的情况,考虑使用 PU Learing ( Postive and Unlabelled Learning )中的 bagging[2]方法,获取一部分可靠的未标签样本标签,进行监督学习;
题目要求找到剩余的500个恶意域名,因此可以推测2w个样本中正样本出现的概率要远大于恶意样本,采样的次数足够大时可以认为预测结果无限逼近原始值;
对剩余的2w多个未标签样本进行随机采样,每次采样均取与恶意域名相同数量的样本(476个)作为正样本,将所有家族的恶意样本均看作是一类,作为负样本,进行监督学习训练,预测剩余的所有样本的概率。
随机采样500次后求预测结果的平均值,将其作为最终的标签,从中找到所有预测结果为恶意的样本。
将第一步预测得到的恶意样本数据作为测试集,题目中给的恶意域名家族标签作为训练集,训练多分类模型,对测试集中的恶意样本进行家族种类预测,最终得到家族类别标签;
针对样本数据大量缺失的情况,使用算法拟合对缺失的数值进行填充
因为有一部分样本数据完整,所以可以根据已有的完整的样本数据,训练回归模型,对缺失值进行预测,通过算法拟合的方式进行填充;
最后对检测模型不断进行调参和优化,根据提交的结果调整检测模型。
选取的主要特征
0x05 猜猜我是谁之黑白域名现形记
题目描述
对给出域名的流量数据进行分析,按照请求特征对域名进行二分类。
题目分析
题目要求的是按照请求特征进行分类,在提供的数据中,包含请求特征的有access.csv, flint.csv。另外,域名的文本特征对分类也有一定帮助(fqdn.csv)。因此,主要从这三个文件中提取特征。
解题过程
特征选取
access.csv:提取有关时间段的特征,包括24个小时内每个域名的被请求总数,以及请求域名的ip数量 ,共48个特征。
flint.csv:提取有关域名解析的特征,包括域名的解析数量,是否包含CNAME解析以及一个域名可以解析到多少个不同地区。
fqdn.csv:提取有关域名的特征信息,包括单词字母数字长度占比以及二级域名的数量。
根据flint.csv中的数据,按照以下方法进行处理
模型训练
在提取了特征之后,使用机器学习模型对的特征进行训练。选择的模型包括SVM,逻辑回归,决策树和随机森林。
将有标签的数据划分成训练集和验证集,对比多种分类算法的F1值。随机森林算法的F1值明显高于其他算法,因此选择随机森林算法。
经过对随机森林算法的一系列调参之后,选择一个最好的结果。
0x06 猜猜我是谁之域名大分类
题目描述
对给出域名的流量数据进行分析,按照请求特征对域名进行聚类,要求簇数不能小于3。
题目分析
题目要求的是按照请求特征进行分类,在提供的数据中,包含请求特征的有access.csv, flint.csv。另外,域名的文本特征对分类也有一定帮助(fqdn.csv)。因此,主要从这三个文件中考虑特征。
解题过程
特征提取
access.csv:每个域名在每小时请求次数总和、每个域名每天请求次数总和
flint.csv:每个域名在不同地区的请求次数(加入后效果不理想,后又删除)
fqdn.csv:域名长度、子域名长度、是否含有子域名、数字占比、单词占比、其他字符占比、单词数量。
根据flint.csv中的数据,按照以下方法进行处理
模型训练
我们尝试了Mean-Shift聚类算法、基于密度的含噪声数据空间聚类算法和KMeans算法
Mean-Shift聚类算法无需提前确定类簇数,可以自动计算类簇数。使用该种方法聚类,产生了大量非常小的类簇,效果不理想。
基于密度的含噪声数据空间聚类(DBScan)无需提前确定最终的类簇数,可以自动计算类簇数。使用该种方法进行聚类,产生了一些离群点,并且有几个类簇非常小,不符合提交要求。
KMeans需要提前给出类簇数。为了确定类簇数,我们尝试了不同的类簇数,并观察最终聚出的每一类的大小,确定几个候选类簇数量。通过检测点检测,最终选择的类簇数是6。
存在的问题
此题得分较低(15分),主要原因应该是这些特征并不能很好的表达域名的特点,需要寻找更加有代表性的特征。等比赛方公开数据的ground truth之后,再对所选特征做进一步分析。
0x07 后记
战队所在的信工所六室威胁情报与威胁发现团队(G3)主要针对在线流量、落地样本(载荷)、安全日志、威胁情报等网络空间典型威胁数据进行分析,研究威胁情报智能处理、对抗性恶意代码分析、可疑网络/终端行为检测挖掘的技术与系统,培养具备高级威胁对抗分析技能的人才。同时,团队还建设和运营了国家网络空间威胁情报共享开放平台CNTIC(公众号cntic2017), 研制了大规模恶意代码智能分析平台iMAS 以及网络恶意通信检测系统,均已应用于国家有关部门和地区的实际工作中。
我们欢迎有识之士(学生或员工)加入,联系方方式jiangzhengwei#iie.ac.cn。
0x08 参考文献
[1]. StackExchange.How does the rand() function in C work?[EB/OL]. https://crypto.stackexchange.com/questions/6760/how-does-the-rand-function-in-c-work, 2020-08-20.
[2]. MordeletF, Vert J P. A bagging SVM to learn from positive and unlabeled examples[J]. Pattern Recognition Letters, 2014, 37: 201-209.
0x09 友情链接
DataCon2020 恶意代码分析冠军writeup