# DGA家族Orchard持续变化,新版本用比特币交易信息生成 DGA域名 **blog.netlab.360.com/orchard-dga/** daji August 5, 2022 5 August 2022 / [Botnet](https://blog.netlab.360.com/tag/botnet/) DGA是一种经典的botnet对抗检测的技术,其原理是使用某种DGA算法,结合特定的种子和当 前日期,定期生成大量的域名,而攻击者只是选择性的注册其中的极少数。对于防御者而言, 因为难以事先确定哪些域名会被生成和注册,因而防御难度极大。 [360 netlab长期专注于botnet攻防技术的研究,维护了专门的DGA算法和情报库,并通过订阅](https://data.netlab.360.com/dga/) 情报的方式与业界分享研究成果。近期我们在分析未知DGA域名时发现一例不但使用日期,还 会同时使用中本聪的比特币账号交易信息来生成DGA域名的例子。因为比特币交易的不确定 性,该技术比使用时间生成的DGA更难预测,因而防御难度更大。 该技术发现于一个名为Orchard的botnet家族。自从2021年2月份首次检测到该家族以来,我 们发现它至少经历了3个版本的变化,中间甚至切换过编程语言。结合长期的跟踪结果和其它 维度的信息,我们认为Orchard会是一个长期活跃、持续发展的botnet家族,值得警惕。本文 将介绍Orchard的最新DGA技术,以及它这3个版本的发展过程。本文要点如下: Orchard是一个使用了DGA技术的botnet家族,核心功能是在受害者机器上安装各种恶意 软件。 从2021年2月至今,我们先后检测到3个版本的Orchard样本,均使用了DGA技术。 Orchard的DGA算法一直未变,但日期的使用方式一直在变,最新版同时支持使用比特 币账号信息来生成单独的DGA域名。 除了DGA,Orchard还硬编码了C2域名。 Orchard目前仍在活跃,致力于门罗币挖矿。 ## 传播方式、规模以及影响范围 Orchard采用了“硬编码域名+DGA”的冗余C2机制,并且每个版本都硬编码了1个唯一的 DuckDNS动态域名作为C2,根据它们的DGA实现方式和硬编码的域名,我们把已经检测到的 Orchard样本分为3个版本: ``` v1, orcharddns.duckdns.org v2,orchardmaster.duckdns.org v3, ojena.duckdns.org ``` 它们的时间线如下: ``` * 2021年3月,检测到v1版本,使用C++开发。结合历史数据,我们将v1首次出现时间提前到2021年2月。 * 2021年9月,检测到v2版本,它使用Golang和C++编写。 * 2022年7月,检测到v3版本,编写语言回到C++。 ``` ----- 这3个版本都支持通过感染USB盘的方式进行传播,这 点跟传统的病毒很像,具体实现参考 后面的“USB感染逻辑”部分。理论上,Orchard也完全可以通过其它方式传播。 利用我们的图系统结合PDNS和其它维度的数据,我们发现v1和v2的C2存在明显的共享IP的情 况,如下图所示。 图系统帮我们找到了更多的C2 IP和域名,详见后面的IoC部分,这里的域名特点是都以 duckdns.org结尾。v3因为比较新,没发现其它的关联域名,下面是v3域名的活跃情况。 能看到它是今年5月上线,然后逐渐活跃,目前应该仍然在活跃期内。 ----- 基于PDNS我们对3个版本的感染规模做了评估,其中v1和v2节点数近千,v3因为出现较晚, 节点数不到500,下面是各个版本域名到具体IP的详细解析数。 ``` # v1, orcharddns.duckdns.org 37, 45.61.185.36 413, 45.61.186.52 1301, 45.61.187.240 207, 205.185.124.143 # v2, orchardmaster.duckdns.org 45, 45.61.185.36 104, 45.61.186.52 659, 45.61.187.240 # v3, ojena.duckdns.org 418, 45.61.185.231 ``` 需要强调的是上面的规模数据只是我们视野内看到的,实际的应该要比这更多。 ## 样本分析 Orchard样本在样本层面多使用loader,用于对抗分析和自我保护。目前看到的Orchard loader 并不固定,即使单个版本也会出现多种loader的情况,比如v1版本的Orchard以base64字符串 的形式存在于loader中,v2/v3版本的样本有的以资源文件的形式存放在loader中。各个版本还 都曾使用过例如VMP、Enigma等虚拟壳来保护自身。总的来说,Orchard的工作流程可以用 下面的图来总结。 Orchard三个版本的功能基本相同,包括: ----- 上传设备及用户信息 响应指令/下载执行下一阶段的模块 感染USB存储设备 下面从DGA算法、C2通信和主机行为等几个维度分别分析3个版本Orchard的核心功能。 ### v1版本 该版本的分析以MD5=5c883ff8539b8d04be017a51a84e3af8的样本为基础。它在运行时首先 释放内嵌的PE文件到自启动目录下,所释放的PE在内存中进行base64解码得到orchard的数 据,随后该PE将System32/SysWOW64下的任一exe作为傀儡进程,来运行保存的orchard代 码。该版本Orchard整体逻辑如下图,主要分为网络通信和USB感染两部分,最终功能取决于 C2下发的具体模块,因此orchard本身可以认为是一个Downloader的角色。 此处主要描述其网络通信过程(三个版本的USB感染逻辑相同,详见USB感染一节)。 C2通信过程较为简单,bot在check-in过程中向C2发送收集到的主机信息,然后等待C2响应的 指令。v1版本所收集信息包括:卷序列号(HWID)、电脑名称、用户名、操作系统名称、系 统版本、已安装的捕获驱动程序名称、杀软信息、父进程文件修改时间、置顶窗口名称及窗口 标题等,这些信息以“[o.r.c.h.a.r.d]”作为分隔符进行拼接后发送,如下图所示。 ----- C2响应数据格式一般为“指令+数据”,指令的功能通过指令码指定。下面是一个具体的C2响 应,其中"[&&]"代表指令码2,代表下载执行,具体处理过程分为2种:响应数据如果是URL, 则下载URL对应的PE并执行;如果是base64编码的内容,则先解码然后执行解码后的数据。 此处响应的数据实际是base64编码的新版本PE文件,相当于升级,这也表明老版本可能已经 废弃。 ----- v1版本一共定义了8个指令,指令码与指令字符串的对应关系如下: ``` 1 \[=] 2 \[&&] 3 \[##] 4 \[###] 5 \[%%] 6 \[%%%] 7 \[#\_#] 8 \[\_\_\] \[>>] \[<<] \[^^] \[\*\] \[\~\] \[@] \[!] \[#\*\#\] \[#@#] ``` 由于某些指令置空,8个指令实际对应三种操作(后续版本大同小异): 指令码1和2:判断响应数据为URL或者PE,如果是URL则下载执行,如果是PE,则创 建进程执行(CreateProcess创建进程、傀儡进程、远程线程注入等)。 指令码3、4、8:终结当前进程删除原始文件,或者重新启动。 指令码7:再次收集C2、port、PID、文件名信息向C2进行发送,示例: orcharddns.duckdns.org[o.r.c.h.a.r.d]5890[o.r.c.h.a.r.d]2260[o.r.c.h.a.r.d]stage3_.exe[o.r.c.h.a.r.d] **DGA算法** ----- v1的DGA以日期字符串(比如 2022/07/05 )作为输入,计算其MD5值,然后将MD5字符串均 分成长度为8的四个子字符串,依次与 .com、.net、.org、.duckdns.org 这4个后缀拼接,得到 每天4组16个DGA域名,算法实现如下。 ``` # 2021/04/15 import datetime import hashlib days=30 for i in range(0, days): datex = (datetime.datetime.now() datetime.timedelta(days=i)).strftime('%Y/%m/%d') print("seed: ", datex) md5 = hashlib.md5(datex.encode()).hexdigest() print('md5: ', md5) dga_list = [] dga_list.append(md5[:8]) dga_list.append(md5[8:16]) dga_list.append(md5[16:24]) dga_list.append(md5[24:32]) for j in range(len(dga_list)): print(dga_list[j] + '.com') print(dga_list[j] + '.net') print(dga_list[j] + '.org') print(dga_list[j] + '.duckdns.org') ``` 示例域名如下: ``` seed: 2022/07/05 md5: 91ac64d29f78281ad802f44648b2137f 91ac64d2.com 91ac64d2.net 91ac64d2.org 91ac64d2.duckdns.org 9f78281a.com 9f78281a.net 9f78281a.org 9f78281a.duckdns.org d802f446.com d802f446.net d802f446.org d802f446.duckdns.org 48b2137f.com 48b2137f.net 48b2137f.org 48b2137f.duckdns.org ### v2版本 ``` ----- v2版本出现了两种编程语言实现的样本,分别是Golang和C++,但是功能相同。这里的分析 [以MD5=f3e0b960a48b433bc4bfe6ac44183b74的Golang样本为例,它的C2初始化函数如下](https://www.virustotal.com/gui/file/5da3a405fea843ed422c06987179e0ac47b915c1d12cc608ce4ecb187edf5f03/details) 图所示,能明显看到硬编码的C2域名。 v2版本开始使用json格式,字段含义相对清晰。其收集的信息跟v1大致相同,包括:卷序列号 (HWID)、电脑名称、用户名、系统版本、杀软信息、活动窗口信息等,新增的字段 有:.net框架版本(比如v2.0.50727)、USB 状态、发包类型及自身版本。下面是一个实际观 察到的版本号信息,Bot_Version=1.2/G可能的解释为:版本=v1.2,编写语言=Golang。 ----- v2版本的C++语言样本集成了同样的C2,上线包中的版本信息则变成了 Bot_version:1/C ,它 所收集的信息如下图所示。 根据代码相似性分析,v2版本的C++样本跟后来的v3版本代码同源,说明后者是从前者进化而 来。 v2版本一共有两种指令: 指令1:终结当前进程删除原始文件,或者重新启动。 指令2:判断响应数据为URL或者PE,如果是URL则下载执行,如果是PE,则创建进程 执行(CreateProcess创建进程、傀儡进程、远程线程注入等)。 **DGA算法** v2版本的DGA算法跟v1相同,差别在于对日期字符串的处理,v2会在日期字符串后拼接硬编 码的域名“orchardmaster.duckdns.org”,形如“2022/07/05orchardmaster.duckdns.org",然后 套用v1版本的DGA算法生成域名。 ### v3版本 v3的开发语言回到C++编写,同样包括C2通信和USB感染功能。C2通信逻辑在一个线程中运 行,同时该线程还包括一个跟XMRig挖矿绑定的辅助线程,当Orchard接收完毕下发的XMrig 程序并创建傀儡进程运行之后,辅助线程会向C2再次发送挖矿相关的硬件信息,尝试从C2读 取挖矿软件的配置,目的是为了检查是否需要动态修改XMRig运行时的配置(XMRig提供了一 套HTTP api,支持动态读取并修改运行时的挖矿配置)。 以MD5=cb442cbff066dfef2e3ff0c56610148f的样本为例,C2通信功能如下。 ----- v3版本在C2通信中同样使用json格式来保存主机信息,发送数据的整体结构为 **Byte_0x46+TotalLen+InfoLen+Info.json。相比v2,v3增加了多个跟挖矿相关的字段,收集** 的信息包括: Active_Window:当前活动窗口名称 Antivirus:杀软信息 Authentiate_Type:Windows身份验证类型 CPU_Model:CPU信息 Camera:是否存在摄像头 Elevated:是否是管理员权限 GPU_Models:显卡信息 Identity:HWID\用户名\电脑名称 Operating_System:系统版本信息 Ram_Size:运行内存大小 System_Architecture:处理器个数 Threads:每个处理器内核个数 Version:Orchard版本 v3的上线包实例如下所示。 ----- C2响应消息的body部分也为json格式,其结构为:TotalLen.dword+ Byte0x46+TotalLen+RespDataLen+RespData.json。v3支持8个指令,对应3种操作: 指令1:收集主机信息/自身运行状态并发送到C2(字段包括Domain、In_Memory、 Install_Path、Is_Patched、Message_Type、Patch_Name、Port、 Power_SaverMode、Process_ID、Process_Name、Process_Path、System_Idle、 System_Uptime) 指令4、6:终结当前进程删除原始文件,或者重新启动。 指令7、8:下载&执行下发的矿机程序 下面是一个实际跟踪到的C2响应指令。 其中Transfer_Port表示希望主机再次向2929进行请求,Message_Type表示指令码,其值为 7,表示下载&执行。 ----- 收到上述指令后,bot再次向C2的TCP 2929端口发起请求,Cuda是Nvidia推出的只能用于自 家GPU的并行计算框架,这里的Cuda_Version为0表示不支持Cuda。 随后C2响应一个XMRig矿机程序,Client接收保存后根据指令7将XMRig注入傀儡进程开始执 行挖矿工作。 分析过程中我们发现v3版本最近在持续分发一个同样的XMRig挖矿程序,后者集成了默认的挖 矿配置信息,私有矿池地址:45.61.187.7:7733 **DGA算法** ----- v3的DGA算法未变,但输入的变化较大。实际上它会生成两组DGA域名,第 组域名的输入 拼接算法是日期字符串+“ojena.duckdns.org”, 形如 “2022-08-02ojena.duckdns.org”。第二组 域名的输入为 `https://blockchain.info/balance?` `active=1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa` 这个URL的返回结果,一个典型的返回结 果如下所示: ``` {"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa":"final_balance":6854884253,"n_tx":3393,"total_re ``` [相关字段的含义可以参考Blockchain的API手册:](https://zh.m.wikipedia.org/zh-hans/Blockchain.com) ``` n_tx:交易数量 total_received:接收比特币总量 final_balance:最终余额 ``` 值得强调的是v3版本并未对返回的结果进行解析,而是作为整体直接输入DGA算法来生成域 名。而钱包地址 `1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa` 据说是中本聪本人所持有的比特 币创世地址。过去的十几年间,由于各种原因,每天都会有人向该钱包转入小量比特币,因此 它是变化的,并且该变化很难预测,因此该钱包的余额信息也可以作为DGA输入。 在我们编写文章时,发现近期已有其他研究人员注意到v3版本这种将比特币账号交易信息用作 DGA输入的现象,所分析结果与我们一致,但对方并没有注意到Orchard其实早已出现。 完整的v3版本DGA算法如下: ----- ``` # 2022/07/05 import datetime import requests import hashlib # cluster 1 days = 30 for i in range(0, days): domains = ['ojena.duckdns.org', 'vgzero.duckdns.org'] for do in domains: datex = (datetime.datetime.now() - datetime.timedelta(days=i)).strftime('%Y%m-%d' + do) print("seed_1: %s" % datex) md5 = hashlib.md5(datex.encode()).hexdigest() print("md5: %s" % md5) dga_list = [] dga_list.append(md5[:8]) dga_list.append(md5[8:16]) dga_list.append(md5[16:24]) dga_list.append(md5[24:32]) for j in range(len(dga_list)): print(dga_list[j] + '.com') print(dga_list[j] + '.net') print(dga_list[j] + '.org') print(dga_list[j] + '.duckdns.org') # cluster 2 url = 'https://blockchain.info/balance?active=1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa' res = requests.get(url) wallet_info = res.text print('seed_2: %s' % wallet_info) md5 = hashlib.md5(wallet_info.encode()).hexdigest() print('md5: %s' % md5) dga_list = [] dga_list.append(md5[:8]) dga_list.append(md5[8:16]) dga_list.append(md5[16:24]) dga_list.append(md5[24:32]) for j in range(len(dga_list)): print(dga_list[j] + '.com') print(dga_list[j] + '.net') print(dga_list[j] + '.org') print(dga_list[j] + '.duckdns.org') ### USB感染逻辑 ``` ----- Orchard的文件感染并非传统的代码插入,而是 种文件替换。当检测到USB存储设备时, Orchard会在设备根目录下创建隐藏目录,遍历所有文件进行感染,并将感染前和感染后的文 件都备份到该隐藏目录下,被感染对象在感染时去掉了类型属性,感染后全部变为exe类型, 并追加了.exe后缀,变成了可执行文件。随后样本会复制自身到被感染目录下并随机命名,该 字符串保存到了被感染文件的资源里。当设备中的被感染文件在新系统中被用户执行后,则会 启动隐藏目录中的样本文件,达到感染传播的目的。 USB感染过程会涉及两个内嵌的PE文件,第一个文件是DLL文件,会被释放 到%LocalAppData%目录下,该DLL被Orchard称作CGO_Helper,主要用于提取和替换被感 染文件的图标,其MD5是10D42F5465D5D8808B43619D8266BD99。第二个文件是exe文 件,MD5为f3c06399c68c5fdf80bb2853f8f2934b,作为存储感染代码的模板文件,被感染文 件的全部数据将被替换为该模板文件的数据。该模板的功能是根据资源中的exe名称寻找隐藏 目录下对应的exe启动执行,所以被感染文件的资源中保存的是备份的Orchard样本名称。 USB感染情况示例如下,被感染文件资源中保存了Orchard样本的名称,当用户点击受感染的 exe,将启动隐藏目录下的Orchard样本文件: ## 总结 Orchard是一个使用了DGA技术的botnet家族,最新版本致力于挖矿,并开始使用中本聪的比 特币账号交易信息这类更难预测的信息作为DGA的输入,增加了检测难度。在1年多的时间 里,Orchard先后出现了至少3个不同版本,编程语言和DGA实现都有变化,这说明Orchard是 一个仍处于活跃期的botnet家族,预计后续会有更多的变种出现,值得我们警惕。对Orchard 我们会持续保持关注,有新的发现会继续公开。 ----- ## 联系我们 感兴趣的读者,可以在 **[twitter](https://twitter.com/360Netlab)** 或者通过邮件netlab[at]360.cn联系我们。 ## IOCs ### C2 ``` orcharddns.duckdns.org orchardmaster.duckdns.org ojena.duckdns.org vgzero.duckdns.org victorynicholas.duckdns.org zamarin1.duckdns.org 45.61.185.36 45.61.186.52 45.61.187.240 205.185.124.143 45.61.185.231 MD5 5c883ff8539b8d04be017a51a84e3af8 f3e0b960a48b433bc4bfe6ac44183b74 9cbe4bd27eba8c70b6eddaeb6707659b cb442cbff066dfef2e3ff0c56610148f 10D42F5465D5D8808B43619D8266BD99 f3c06399c68c5fdf80bb2853f8f2934b 19159280736dbe6c11b7d6a57f6bb7b9 b5a6f78d5575a60316f4e784371d4f8c 3c20ba851edecd28c198691321429883 2b244a39571ab27f7bb4174d460adeef ae1e9b3621ee041be6ab5e12bff37c53 00b1620f89b7980b34d53737d9e42fd3 4d2445a43591d041cabbbf3dfca6dfbd 私有矿池 45.61.187.7:7733 ``` -----