无视AWS云服务器防火墙的恶意软件Cloud Snooper
2020-03-02 11:00:00 Author: www.4hou.com(查看原文) 阅读量:192 收藏

导语:SophosLabs安全团队在Amazon Web Services(AWS)云服务器中发现了一起复杂的恶意软件感染事件,攻击者采用了独特的技术组合来逃避检测,能让恶意软件无视防火墙与C2服务器自由通信。

近期,SophosLabs安全团队在Amazon Web Services(AWS)云服务器中发现了一起复杂的恶意软件感染事件,攻击者采用了独特的技术组合来逃避检测,能让恶意软件无视防火墙与C2服务器自由通信。

此次攻击虽然在AWS上发生,但并不是AWS本身的问题,攻击者滥用合法流量(例如普通Web流量)来承载C2流量,这种方法可以绕过大多防火墙的限制。

该恶意软件被命名为Cloud Snooper,受感染的系统同时运行Linux和Windows EC2实例。鉴于攻击的复杂性和对APT工具的使用,该恶意软件背后的可能是APT组织团伙在运营。

异常流量报警

AWS安全组(SG)检测到异常流量后进行了适当的调优,设置为仅允许入站HTTP或HTTPS流量,但受感染的Linux系统仍然在监听端口2080/TCP和2053/TCP上的入站连接。

对该系统分析显示,存在一个rootkit,该rootkit使操作员能够通过AWS SG远程控制服务器,且不仅限于在Amazon云中执行操作,还可以与边界防火墙后的任意服务器(甚至是本地服务器)上的恶意软件进行通信和远程控制。另外,在其他受感染的Linux主机中也都发现了相同或类似的rootkit。

之后,研究人员又发现了一个受感染的Windows系统,它也有一个相似的后门与C2通信,这个后门基于Gh0st RAT恶意软件源码。

目前还有一些问题尚未解决,比如不清楚攻击者是如何破坏客户端系统的,一个猜想是SSH入侵。

攻击流程

在开始技术说明之前,可以先了解下Cloud Snooper的攻击流程。

在上图中,城堡代表了目标服务器,在本例中由Amazon Web Services(AWS)托管。在其外围,AWS安全组(SG)——一组在协议和端口访问级别提供安全性的防火墙规则——限制了入站网络流量。

举个例子,你可以设置一个AWS SG,仅允许Web流量(即到达端口80或443的TCP数据包)到达你的服务器,而任何其他端口的网络流量则无法通过此SG。

此次的感染过程包含一个负责检查网络流量的rootkit,还有一个后门,攻击者利用此rootkit 向后门发送命令,并从后门接收数据。

为了绕过防火墙规则(图中的警卫),攻击者向端口上的web服务器发送看似无害的请求(图中的披着羊皮的狼)来与rootkit通信。侦听器会在入站流量到达Web服务器之前对其进行检查,拦截这些特制的请求,并根据请求的特征将指令发送给恶意软件。

接着侦听器将重构后的 C2命令发送给后门木马(由rootkit安装),如果是通过后门窃取敏感数据的指令,则需要将窃取数据与C2流量一起传回,rootkit将再次对数据做伪装——让狼再次穿上羊皮大衣。到达外部后,C2流量会将收集的数据传递回攻击者。

在整个操作过程中,正常的网络流量(图中的绵羊)在警卫的监视下不断地进进出出,看上去C2流量与合法的Web流量似乎没有什么区别。

恶意样本

下列搜集到的样本中,有一些是直接相关的,还有一些则属于不同的恶意软件家族,所有这些样本都是从同一服务器中收集的,因此我们将它们视为同一工具集。

在调查过程中发现的10个样本,可将其细分为:

image.png

image.png

Cloud Snooper通信处理程序

恶意软件核心部分是一个名为snd_floppy的文件,这是一个内核模块,使用Netfilter钩子(NF_INET_LOCAL_IN和NF_INET_LOCAL_OUT)设置网络包过滤器。该组件能让攻击者绕过AWS EC2服务器防火墙与恶意软件通信。

NF_INET_LOCAL_IN在包到达目的端口之前被触发。已安装的钩子处理程序将检查每个IPv4数据包的套接字缓冲区,查找隐藏在标头中的命令——命令来自攻击者数据包的源端口号,包括:1010、2020、6060、7070、8080、9999。

防火墙通常会阻止计算机接收发送到任意目标端口的流量,但不会关注源端口,因为源端口通常是临时的,与服务器或它所承载的服务无关。

在典型的云实例中,可以将服务器设置为接收端口80/TCP(用于HTTP)和端口443/TCP(用于HTTPS)上的任何IP地址的流量,防火墙将允许这些端口的任意流量通过服务器。只要进入这些标准端口之一的流量符合通信处理程序寻找的模式,它就会执行一个内置的指令。其他任何内容都将被忽略,服务器将正常为浏览器提供web页面。

例如,如果通信处理程序收到一个源端口为6060的TCP SYN包,恶意软件将解密一个嵌入的文件(RC4加密,密钥为“YaHo0@”),并将解密后的文件以“/tmp/snoopy”命名,等待半秒钟后使用call_usermodehelper() syscall作为用户模式应用程序执行。之后再删除/tmp/snoopy文件,因此snoopy应用程序虽然在内存中运行,但不会存在任何物理文件。

如果该命令是TCP SYN包的9999,则/tmp/snoopy进程将通过将以下命令传递给call_usermodehelper() syscall来自动终止(以防OS支持killall)。

/bin/sh -c /tmp/snoopy
rm -rf /tmp/snoopy
killall /tmp/snoopy

注意:在已经运行的情况下再次执行snoopy无效;通过文件锁定机制,snoopy可以确保仅运行一个实例,否则它将输出:

[ERROR] there is already a instance.

这是NF_INET_LOCAL_IN钩子处理程序的逻辑,它通过各类源端口侦听发送到服务器的SYN数据包:

if tcp:
    if tcp.src_port == 6060:
        if tcp.flags == SYN:
            drop_payload()        # drops/runs snoopy
            return NF_STOP
    elif tcp.src_port == 7070:
        tcp.dst_port = 2080
        adjust_tcp_checksum()
        return NF_STOP
    elif tcp.src_port == 9999:
        if tcp.flags == SYN:
            kill_payload()        # kills snoopy process
            return NF_STOP
    elif tcp.src_port == 2020:
        return NF_STOP
    elif tcp.src_port == 1010:
        tcp.dst_port = 22
        adjust_tcp_checksum()
        return NF_STOP
    else:
        return NF_ACCEPT
elif udp:
    if udp.src_port == 8080:
        udp.dst_port = 2053
        adjust_udp_checksum()
        return NF_STOP
else:
return NF_ACCEPT

NF_INET_LOCAL_OUT钩子处理程序的逻辑如下:

if tcp:
    if tcp.dst_port == 7070:
        tcp.src_port = 443        # or, 80 in another variant
        adjust_udp_checksum()
        return NF_STOP
    if tcp.dst_port == 2020:
        return NF_STOP
    if tcp.dst_port == 1010:
        tcp.src_port = 443        # or, 80 in another variant
        adjust_udp_checksum()
        return NF_STOP
    else:
        return NF_ACCEPT
elif upd:
    if udp.dst_port == 8080:
        udp.src_port = 53
        return NF_STOP
else:
return NF_ACCEPT

激活payload

为了激活payload(snoopy),攻击者会发送以下数据包:

接下来,C2将访问snoopy模块,基于tcp的源端口为7070,基于udp的源端口8080:

在返回的过程中,NF_INET_LOCAL_OUT钩子处理程序再次重新构建包,确保端口还原回输入数据包的原始端口,这样C2流量就能透明地通过AWS SGs允许的端口:

如果这个钩子返回NF_STOP,那么链中的其他Netfilter钩子(例如防火墙输入/输出规则)将不会处理这个包,这可能是TCP命令2020的目的:绕过其他Netfilter钩子。

在Netfilter接收到源端口为1010 / TCP的入站流量的情况下,它将内容定向到安全Shell (SSH)端口22/TCP。对于出站流量,我们已经看到有两个变体使用端口80或端口443,能让SSH连接绕过对端口22流量进行IP限制的AWS SG。

因此,snd_floppy rootkit的最终目的是为snoopy usermode进程提供一个隐蔽的控制通道。

这种隐蔽控制通道可以通过AWS SGs允许的任何端口建立,无论是80、443、22还是其他端口。

从外部看,受影响的系统将显示异常大的流量,来自远程端口6060、7070、8080和9999。

下一节将细述snoopy模块。

snoopy模块

snoopy是一种后门木马,既可以作为命令行工具,又可以作为守护程序执行。后门的内部版本为3.0.1-2.20170303。

它在受感染的系统上打开HTTP和/或DNS服务,对流量进行隧道传输,并作为反向SOCKS5代理服务器和客户端运行。

比如传入的控制流量可以中继到其他服务器。

使用-h选项运行时,将显示以下内容:

Usage: rrtserver [OPTIONS]
OPTIONS:
-h
-d
-s IPv4[:PORT:{udp|tcp}:{dns|http|none}]

-h:输出上述内容

-d:将工具作为守护程序运行

-s:允许指定一个服务器地址来绑定监听套接字、它的端口号和用于通信的协议:基于udp的DNS或基于tcp的HTTP

snoopy二进制文件运行需要root权限,运行时,调用geteuid()来获取用户ID。如果失败,则打印下行文字并退出:

"Administrator privileges are required."

它将工作目录设置为/ tmp,并获取文件/ tmp / rrtserver-lock的锁,锁的目的是确保仅运行一个版本。

HTTP通信在端口2080上接收,DNS通信在端口2053上接收。

注意:端口号2080和2053是默认端口号,其他端口号也可用来执行此工具。

snoopy能解析接收到的DNS / HTTP流量,提取其中的隐藏命令——这些命令称为“ rrootkit消息”,通过魔术值标头或标记来区分。

例如,为了在HTTP流量中找到“rrootkit消息”,Snoopy解析HTTP请求,看看它的标头是“GET /* HTTP/1.1\r\ndata:”还是“HTTP/1.1 200 OK\r\ndata:”。

如果魔术值标头为0xE381B7F5,则此类数据称为msg-data。接收到的msg数据用RC4解密,密钥是字符串“A YARN-based system for parallel processing of large data sets”。

接着启动几个附属组件,由这些组件处理接收到的msg数据,而每个msg-data中不同的魔术值标头也决定了数据由哪个组件处理。

这些组件分别为:

1.view-shell(魔术值标头0xFC72E392):允许远程Shell的pty(pseudo terminal,伪终端)

· 清除HISTFILE变量,确保/ bin / sh执行不会留下任何历史记录

· 使用/ bin / sh执行收到的命令

2.view-file(魔术值标头0xFC72E393):文件管理器,接受3个命令:

· ' get ' -读取文件

· ' put ' -保存文件

· 其他任意命令-用popen() syscall执行文件

3.view-proxy(魔术值标头0xFC72E394):接受以下命令的代理服务器:

· ‘exit’ 或 ‘quit’  –退出代理服务器

·  'socks5'–启动SOCKS5代理服务器,通过使用'-u'和'-p'参数传递的用户名/密码来提供身份验证

· ‘rcsocks-cmd: socks is closed.’ –关闭SOCKS代理

SOCKS5服务器基于开源sSocks代理实现。

4. view-pipe(魔术值标头0xFC72E398):p2p通信器,接收命令“ pwd”,“ exit”,“ quit”,“ connect”:

在收到“connect”命令时,它接受与命令行工具相同的参数(服务器IP、端口、协议),并开始向另一个对等点发送隧道命令。该隧道似乎用于建立与其他对等点的连接,与其他对等点的协商协议中包含消息“ rrootkit-negotiation:hello”。建立连接后,记录的消息将显示已连接的对等节点,新网络节点如下所示:

· “view-pipe: left[address, port]->right[address, port].”

· “view-pipe: the network node is opened.”

5.view-myproto(魔术值标头0xFC72E397):“ ping” /“ pong”;根据接收到的标志,它要么:

· 收到一条消息“rrootkit-negotiation: hello”,然后返回“rrootkit-negotiation: ok, go on”

· 检查接收到的消息是否为“rrootkit-negotiation: ok, go on”

6.loop-notifier–创建进程间通信(IPC)的数据通道。

后门允许IPC管道作为备用控制通道。

日志记录

snoopy以明文形式存储调试消息,但如果将内部日志级别设置为0 (none),则不会输出任何调试消息,这些消息仅用于恶意软件的测试阶段。

一些调试信息是中文的:

· 远程路径太长! – The remote path is too long!

· 远程文件不存在! – The remote file does not exist!

· 远程内存空间分配失败! – Remote memory space allocation failed!

· 远程路径不存在! – The remote path does not exist!

· 远程文件已存在! – The remote file already exists!

· 连接失败! – Connection failed!

· 连接成功! – Connection succeeded!

· 参数错误! – Parameter error!

其中一些消息表明创作者的英语能力不佳,比如下列语法错误:

· view don’t found

· view-shell: data do not belong to SHELL

构建客户端

了解了C2协议的工作原理后,可以构建一个客户端来直接或通过snd_floppy rootkit与snoopy对话。客户端的作用是可以ping同一网络中的主机,看看它是否被感染。其次,如果主机被感染,客户端可以远程消毒,指示snoopy执行它的消毒程序(见下面的rmmod命令)。

下面的截图演示了客户端的实际操作。snd_floppy rootkit在端口22上拦截流量,即使该流量发往SSH守护程序(在下图中为981 / sshd)也是如此,接下来将内部流量重新定向到到snoopy模块。

只要rootkit处于活动状态,攻击者就可以尝试通过防火墙允许的任何端口控制流量(截图显示,使用端口21和24没什么区别——数据包仍由rootkit重新导向到后门)。

Gh0st RAT(Linux版本)

除了这些样本之外,我们还恢复了另一个Linux后门,该后门没有打开任何端口。相反,它依赖于C2轮询机制。

对该样本功能的分析表明,它属于Gh0st RAT,只有它是为Linux编写的版本。

很难判断Gh0st是否一直作为一个多平台的RAT病毒存在,抑或攻击者是否在Windows Gh0st的源代码被泄露到网上之后开发了一个基于linux的Gh0st。

归根结底,使用统一的配置格式和C2协议将客户端部署在不同的平台上,同时为所有这些客户端提供一个服务器,是有意义的。

不过,我们的重点依然是在样本的实际作用上。

/ bin / snort是与远程C2联系、获取并执行命令的后门,其内部配置文件进行了RC4加密,密码为“r0st@#$”:

185[.]86[.]151[.]67:443;|1;1;1;1;1;0;0;|10-20;|10

'1; 1; 1; 1; 1; 0; 0;' 表示一周中的七天。

'10 -20;' 可能表示工作时间(上午10点至晚上8点),因此当前工作日和当前小时应该与配置中的内容匹配。

如果没有匹配项,bot程序会在7分钟(423.756秒)多一点的时间内进入睡眠状态,然后再次检查时间。

如果匹配,则将尝试到达C2;如果不能,在一分钟后重试。

到C2的流量使用双RC4加密,基于当前时间随机生成密钥。

后门包含以下命令:

1.bot程序会清除环境变量HISTFILE,以确保/ bin / bash执行不会保留任何历史记录;C2会响应一个字符串,bot将TERM变量设置为该字符串;接下来,bot接收命令并使用/ bin / bash执行,无论命令是否带有'-c'(允许执行引号内提供的命令);执行命令的结果被发回C2。

2.文件操作:

· 找到并获取指定文件的时间戳

· 重命名指定文件

· 递归删除指定目录中的所有文件

3.更多文件操作:

· 读取指定文件的内容

· 递归搜索文件

· 将数据写入指定的文件

· 创建指定目录

4.接下来的两个命令使用fcntl() syscall和fork子进程操作文件描述符

5.接收数据并将其保存到本地文件/usr/include/sdfwex.h

似乎/usr/include/sdfwex.h包含C2起始连接的时间戳(年,月,日,小时,分钟)。

如果bot无法打开该文件,它将尝试打开/tmp/.llock,如果也无法打开,将跳过时间戳检查,并继续尝试连接到C2。

样本的其他变体使用不同的配置,如:

cloud[.]newsofnp[.]com:443;|1;1;1;1;1;1;1;|00-24;|1
load[.]CollegeSmooch[.]com:82;|1;1;1;1;1;1;1;|00-24;|10

发送到C2的信标信号中包含以下信息:

· 主机名和IP地址

· 平台类型,从/proc/version读取,如'x86_64'

· Linux版本的全名,从/etc/issue.net和/etc/issue读取,例如:

     ‘Red Hat Enterprise Linux Server release 6.10 (Santiago)’

     ‘Ubuntu 16.04.5 LTS’

与C2的通信始终使用定制算法进行加密,该算法基于时间的随机RC4密钥,且具有额外加密层。

Windows恶意软件

NSIProvider.dll是一个恶意Windows服务DLL,在svchost.exe下执行。

服务名称为NSIProvider,注册时带有描述名称“ Netword Store Interface Provider”。

注意:“ Netword”和“ d”。

如图所示,此DLL被严重混淆。一旦作为服务启动,它就会吐出记录操作的调试消息。

Sysinternal的DebugView显示以下消息:

00000000 0.00000000 [4052] DLL_PROCESS_ATTACH.
00000001 0.00489140 [4052] Rundll32Entry()
00000002 0.01733349 [4052] ServerLoadPayload()
00000003 0.01749189 [4052] Get Module File Name.
00000004 0.01753826 [4052] Get Payload File Name.
00000005 0.01757095 [4052] Switch to payload directory.
00000006 0.01768074 [4052] Read Payload File.
00000007 0.01811264 [4052] Decrypt Payload Data.
00000008 0.06122175 [4052] Verify Payload Data.
00000009 0.06732560 [4052] ServerExecutePayload()
00000010 0.06740102 [4052] Call Shellcode.‬‬‬

加载后,DLL会找到加密的负载文件并将其加载到内存中。

步骤是:

· 使用GetModuleFileName() API获取当前模块文件名,即%PATH%\NSIProvider.dll

· 将当前模块文件名与“ .crt”连接,例如%PATH%\NSIProvider.dll

· 使用VirtualAlloc()分配内存,并将负载文件读入内存

· 初始化由256个DWORD组成的置换表,排列表的每个值,计算如下:

*ptr= ((*ptr >> 1) & 0x54384748 | ~(*ptr >> 1) & 0xABC7B8B7) ^ 0x467F3B97;
...
PERM_TABLE[*index] = *ptr;

· 开始解密循环——在这个循环中,加密负载的每个字节减去一个密钥值;密钥值本身根据之前的密钥值、解密字节的当前索引和排列表在每次迭代中计算的:

ptr = __ptr_index++;
val = PERM_TABLE[((*ptr & 0x67612505 | ~*ptr & 0x989EDAFA) ^ (KEY & 0x67612505 | ~KEY & 0x989EDAFA)) & ((*ptr & 0x67612505 | ~*ptr & 0x989EDAFA) ^ (KEY & 0x67612505 | ~KEY & 0x989EDAFA) ^ 0xFFFFFF00)];
KEY = (val & 0x432AA81D | ~val & 0xBCD557E2) ^ ((KEY >> 8) & 0x432AA81D | ~(KEY >> 8) & 0xBCD557E2);

解密后的有效负载将显示一个校验和,由一些0字节组成,其后是初始shellcode:

解密的负载blob被复制到新分配的内存缓冲区中,并调用初始shellcode(从上图中的字节EB 17 58开始)。

然后,初始shellcode将使用从0x2B开始的XOR密钥解密该Blob的其余部分,然后根据解密字节的索引进行递增,即XOR密钥值为:0x2B,0x2C,0x2E,0x31等。

当Blob其余部分解密时,配置文件也被解密,然后是其他部分。

在初始shellcode解密完成之后,完全解密的Blob将包括:

· 初始shellcode

· 解密的配置:

Microsoft.Windows.BNG|‪ssl[.]newsofnp[.]com:443‬;|1;1;1;1;1;1;1;|00-24;|1

· Zlib压缩的LIBEAY32.dll(77,871字节,解压后为167,936字节)

· Zlib压缩的LIBEAY32.dll(386,876字节,解压后为851,968字节)

· 后门,以第二阶段shellcode的形式实现

解码后,将调用第二阶段的shellcode,即后门本身。

在获得控制权后,后门会通过使用硬编码的API哈希值来动态获取所需的所有API。 为了从API名称中找到匹配的哈希,shellcode用到了ROR-13算法,并做了略微改动,其唯一的区别是检查零字节是否在循环末尾,因此对于终止的零字节具有一个额外的ROR。

所有必需的DLL是动态加载的。

接下来,后门解压2个存根并作为DLL加载,这两个DLL的内部名称均为LIBEAY32.dll。

这两个DLL都依赖于libeay32.dll的较早版本(2004)生成,下面是在这些DLL的主体中找到的一些字符串:

MD2 part of OpenSSL 0.9.7d 17 Mar 2004
MD4 part of OpenSSL 0.9.7d 17 Mar 2004
MD5 part of OpenSSL 0.9.7d 17 Mar 2004
SHA part of OpenSSL 0.9.7d 17 Mar 2004
SHA1 part of OpenSSL 0.9.7d 17 Mar 2004

后门通过这些DLL来实现与C2通信所需的加密功能。

配置格式与ELF二进制文件一致,即七个“ 1;” 表示bot应每周7天(全天候(00-24))处于活动状态,C2通过HTTPS进行通信。

Gh0st RAT使用了相同的配置。

就像上述/ bin / snort一样,bot还会检查当前的日期和时间是否与配置中指定的日期时间匹配。如果没有匹配项,则bot会进入超过7分钟(423.756秒)的睡眠状态,接着再次检查时间。

下面的代码片段演示了/ bin / snort可执行文件中指定的423,756毫秒延迟,与在其Windows版本中对应相同:

ELF可执行文件:/ bin / snort

image12.png

Windows shellcode:

image13.png

在Linux上,数字423,756乘以1,000后传递给usleep() syscall,该syscall的参数以微秒为单位。

在Windows上,将相同的数字传递给Sleep() API,后者接受参数的时间以毫秒为单位。

在两种情况下,实现的延迟都是相同的:7.062秒。

结论

这个案例非常有趣,因为它展示了现代攻击的真正多平台特性。一个资金充足、有能力、有决心的攻击者不太可能受到不同平台所施加的边界限制。构建一个统一的服务器构架,为不同平台上工作的各种代理提供服务,这对他们来说非常有意义。虽然AWS SG提供了强大的边界防火墙,但并不代表网络管理人员就能把网络安全完全托付于它。对SSH服务器而言,还应有其他额外的措施来增强其攻击抵抗力,让其成为稳固可靠的通信守护程序。

Cloud Snooper恶意软件详细报告请参见此处

IoC

本地主机上开放端口

· tcp 2080

· udp 2053

· tcp 10443

案例

user@host:~$ sudo netstat -peanut | grep ":2080 \|:2053 "
tcp  0  0 0.0.0.0:2080    0.0.0.0:*    LISTEN  0  34402  2226/snoopy
udp  0  0 0.0.0.0:2053    0.0.0.0:*            0  34398  2224/snoopy

检查这些端口是否在IP 192.168.5.150的远程受感染主机上打开:

user@host:~$ sudo nmap 192.168.5.150 -p 2080
...
PORT     STATE    SERVICE
2080/tcp filtered autodesk-nlm
user@host:~$ sudo nmap 192.168.5.150 -p 2053 -sU
...
PORT     STATE    SERVICE
2053/udp filtered lot105-ds-upd

来自远程端口的入站连接:

1010, 2020, 6060, 7070, 8080, 9999

域名:

· cloud[.]newsofnp[.]com

· ssl[.]newsofnp[.]com

· load[.]CollegeSmooch[.]com

IP

· 62[.]113[.]255[.]18

· 89[.]33[.]246[.]111

· 185[.]86[.]151[.]67

文件名

· /tmp/rrtserver-lock

· /proc/sys/rrootkit

· /tmp/rrtkernel.ko

· /usr/bin/snd_floppy

内核模块:

· snd_floppy

案例:

user@host:~$ sudo lsmod | grep "snd_floppy"
snd_floppy 316594 0

系统日志消息:

“…insmod: ERROR: could not insert module /usr/bin/snd_floppy: File exists”
“…kernel: snd_floppy: loading out-of-tree module taints kernel.”
“…kernel: snd_floppy: module verification failed: signature and/or required key missing – tainting kernel”

本文翻译自:https://news.sophos.com/en-us/2020/02/25/cloud-snooper-attack-bypasses-firewall-security-measures/如若转载,请注明原文地址


文章来源: https://www.4hou.com/posts/mMvG
如有侵权请联系:admin#unsafe.sh