自2019年9月份开始,我们持续发现一类命名为Mozi.a和Mozi.m的IOT样本,分别运行在ARM CPU和MIPS CPU架构的物联网设备上。经过分析确认这是Hajime之后,另一个基于DHT协议实现的P2P Botnet。
Mozi主要通过Telnet弱口令和一些已知的漏洞进行传播。

| |
| |
| |
| |
| |
| Eir D1000 Wireless Router RCI | |
| CCTV/DVR Remote Code Execution | |
| Netgear cig-bin Command Injection | |
| Netgear setup.cgi unauthenticated RCE | |
| UPnP SOAP TelnetD Command Execution | |
| HNAP SoapAction-Header Command Execution | |
| JAWS Webserver unauthenticated shell command execution | |
Mozi加入基于DHT的P2P网络后,会同步Config文件,并根据Config文件里的控制字段执行相应功能,事实上攻击者也正是通过Config文件对Mozi下达控制命令。 每个Mozi样本都硬编码了一个XOR加密的初始Config,长为528字节。其中前428字节是配置数据,其后96字节是数字签名,最后4字节是flag字段,用来控制是否更新Config文件。

Config里字段大致分为辅助字段、控制字段、子任务字段。辅助字段主要是信息说明,比如本例的[ss]bot[/ss],用来表示基于本Config,当前节点的角色是bot。控制字段用于更新节点数据,比如[hp]88888888[/hp]是生成DHT节点id时所使用的前缀。子任务字段最重要,用于开启任务,执行攻击者的指令,主要有:
[atk] DDoS攻击
[ud] 更新自身
[dr] 从指定url下载payload并执行
[rn] 执行系统或者定制化命令
[idp] 报告bot信息,本例是http://ia.51.la/
很遗憾,目前看到样本的初始Config都不包含[atk]、[ud]、[dr]、[rn],在长时间运行后,同步Config时也没发现。就是说,目前我们长时间运行样本后,暂时还没有接收到攻击者的任何命令。但收到过一些角色是ftp的节点同步来的Config。

Mozi使用简单扩展的DHT协议建立P2P网络,这样既然可以用标准的DHT能够快速组网,也可以把够将自身的恶意流量隐匿于海量的正常DHT流量中,躲避检测。Mozi使用1:v4:(4byte flag)来区分正常的DHT节点和Mozi节点流量,4字节flag定义如下:第1字节为随机生成,第二字节为硬编码的0x42,或来自Config里的版本字段[ver]。第3,4字节通过一定算法对"1:v4:(randbyte)42"计算得来。算法如下:
如果接收到其它节点的数据,发现了1:v4:(4byte flag),且flag满足上述算法,则认为对方是Mozi节点,继而和对方同步Config文件。如果没有,则认为是正常的DHT节点,按照标准的DHT协议回应。同样它自己发送给其它节点的数据也一定包含1:v4:(4byte flag)。Mozi运行后,按照标准DHT协议,首先向初始节点发送ping请求,来获取临近节点列表。
ping请求之后即进入循环请求和响应其他节点的流程,它接收到数据,首先搜索是否存在1:v4:,并且对4byte flag进行校验。所谓扩展的DHT协议,是指Mozi在标准的DHT协议解析函数之后,追加了自己的响应方式。Mozi节点接收到的数据有两大类,一类是非DHT协议的请求数据,一类是DHT协议的请求数据。二者通过查找1:y1:q来区别,正常的DHT协议请求肯定包含1:y1:q。对于非DHT协议的请求,如果报文长度小于99字节,则把自身的Config数据发送给请求方。
同样,如果一个Mozi节点想获取其它Mozi节点的Config数据,则向对方发送小于99字节的非DHT请求即可。它这儿只判断了长度,没判断数据内容,所以其实是随机的数据。下图即发送小于99字节的随机数据,长度也是随机的,有82,29不等,来获取对方的Config:
对大于99字节的非DHT数据,则认为收到的数据正是加密的Config,会保存起来,并解析其中的字段,执行相应任务。 对于DHT请求,支持ping、find_node、get_peers。其中对于ping,直接按照标准的DHT协议返回pong。 对find_node、get_peers请求合二为一,如果不是来自Mozi节点,仍然按照标准的DHT协议回应对方,把自身临近节点列表发送给对方。如果它们是来自Mozi节点的请求,还可能把自身配置数据发送给请求方法。而判断find_node、get_peers是否来自其它的Mozi节点,正是依据请求数据里是否存在1:v4:(4flag)。
上图是向IP为114.15.155.252的Mozi节点发送了find_node请求之后,该节点判断请求来自Mozi节点,返回自身Config数据,即0x151529d2e6起始到结尾。随后继续发送find_node请求,这次114.15.155.252节点返回的是它自身临近的节点数据,即长度为277那一帧,见下图: