首页
社区
课程
招聘
[原创][翻译]Melting Ice-用几个简单的步骤跟踪IcedID服务器
2021-6-1 11:32 4344

[原创][翻译]Melting Ice-用几个简单的步骤跟踪IcedID服务器

2021-6-1 11:32
4344

备注

  • 原帖地址:https://research.checkpoint.com/2021/melting-ice-tracking-icedid-servers-with-a-few-simple-steps/

  • 原帖标题:Melting Ice – Tracking IcedID Servers with a few simple steps

  • 原帖信息:May 26, 2021  Research by: Alex Ilgayev

简介

追踪僵尸网络通常需要大量的努力、时间和威胁情报知识。如果是多阶段的复杂恶意软件家族,如IcedID、Emotet和QakBot,跟踪的难度就更大了。因此,作为恶意软件分析师,我们倾向于寻找尽可能多的自动化过程--收集大规模的样本,识别它们,提取它们的配置,然后让这些产生我们感兴趣的价值,如更清晰的威胁情报图片或更最新的域信誉引擎。


虽然恶意软件分析的生活往往像上面描述的那样困难,但它不一定是这样。有时,如果我们很聪明,10%的工作会得到我们感兴趣的90%的结果。在这篇文章中,我们展示了这样一个巧妙的方法,并展示了如何快速跟踪IcedID C&C服务器,并且不需要跟踪或分析任何样本。

IcedID背景

IcedID banker恶意软件最早出现于2017年9月,此后取得了重大进展。这种威胁,也被称为BokBot,在过去的一年中不断增长,并拥有广泛的恶意功能,如浏览器拦截,凭证盗窃,MiTM代理设置和VNC模块等。

MalwarebytesGroup-IBBinary Defense过去的出版物对该僵尸程序的内部功能,包括感染链和恶意组件进行了彻底描述。


根据二进制防御研究人员提出的最新感染链,最近迭代的IcedID包含三个恶意组件--包含恶意宏的进入点DOC/XLS;一个第一阶段的payload;以及最后一个第二阶段的payload,它本身由两个子部分组成--一个64位DLL加载器,以及被伪装成".dat "文件的加密的实际僵尸程序。


每个第二阶段的payload通常包含2-4个独特的嵌入式域名,这些域名都可以解析到同一个IP地址。假设我们设定一个目标,跟踪这些域名/IP并阻止它们;自然,我们对最快速和无痛的方式感兴趣。


受害者的通信协议是HTTPS,所以我们检查了捆绑的TLS证书。正如我们在下面观察到的,IcedID的人更关心RSA-2048提供的硬性具体保证,而不太关心遵循安全准则;该证书签发给默认名称为“ Internet Widgits Pty,Ltd”的机构,该机构位于“某个州”。

IcedID C&C证书样本:

如果我们把这个IcedID证书和一个默认的自签名证书进行比较,最明显的区别是通用名称字段。公共服务器的FQDN(例如)应该在这个字段中出现,而不是像本例中的Checkpoint.comlocalhost那样。


你可能明白这是怎么回事;我们立即开始扫描广泛的网络,寻找其他呈现这种证书的服务器。

枚举服务器

我们不愿重复发明,选择使用流行的互联网扫描平台Censys来创建一份潜在的C&C候选人名单。像Shodan这样的其他网络扫描平台也可以用于此目的。


Censys引擎为我们提供了大量的证书查询控制。经过一些调整和调整,我们构造了以下查询:

443.https.tls.certificate.parsed.issuer_dn: "CN=localhost, C=AU, ST=Some-State, O=Internet Widgits Pty Ltd" and 443.https.tls.certificate.parsed.subject_dn: "CN=localhost, C=AU, ST=Some-State, O=Internet Widgits Pty Ltd"

Censys的证书结果之一:

如果您怀疑在证书中使用通用名称的唯一性,可以通过一个简短的实验轻松地证明这一点:我们搜索到的几十个服务器看起来似乎很多,但如果您在搜索查询中省略了要求,结果将在千分之一的大小和数量上爆炸式增长:localhostCN=localhost

目前,我们不能假设这些服务器中的每一个都是活动的IcedID恶意C&C,所以我们需要验证它们。幸运的是,这是可能的,这要归功于我们在研究过程中发现的另一种独特的特性。

验证服务器

当我们对僵尸程序的功能进行逆向工程时,我们注意到僵尸程序在与C&C服务器通信之前做了一个相当有趣的测试。下面的代码是一个回调函数的一部分,在与C&C.WinHttpSendRequest联系之前被调用。

证书验证代码:


简单地说,这段代码在证书的公钥上运行Fowler-Noll-Vo 32位哈希函数,并将其与证书的指定序列号进行比较。只有当比较结果吻合时,通信才会继续进行(或用XOR-ed值)。0x384A2414


证书序列号字段由证书颁发机构分配,并为每个生成的证书提供一个唯一的标识符。证书颁发者必须确保没有两个具有相同证书颁发者DN的不同证书包含相同的序列号,但没有人能够保证这一点。


在我们的案例中,证书是自签的,恶意软件运营商根据上述逻辑唯一地分配其C&C序列号字段。自己使用这种验证算法,针对一个可疑的服务器,我们可以确保它是IcedID基础设施的一部分。我们在附录A中提供了一个简单的python脚本来验证这个逻辑,针对一个提供的远程服务器。


应用该方法,我们发现之前的大多数潜在结果都与IcedID有关,并将名单缩小到52个服务器。考虑到独特的证书属性和不常见的哈希函数,我们可以安全地推断这些服务器是IcedID C&C基础设施中的组成部分。有了这个名单,我们去仔细查看了这些服务器。

服务器分析

通过分析他们面向互联网的标语,我们可以发现大多数部署的服务器有几个类似的属性。最常见的属性是开放端口、操作系统和网络服务器。

开放的端口 - 所有的服务器都有443端口,94%的服务器还监听80端口,77%的服务器监听SSH端口(22)。

操作系统 - 77%的服务器运行的是Debian操作系统。

网络服务器 - 94%的服务器运行nginx网络服务器。

我们还可以看到,大多数的服务器居住在罗马尼亚、美国和德国。

IcedID服务器的位置:

另一个分析角度是通过被动DNS服务,如RiskIQ。使用这种服务使我们能够为我们拥有的每个IP地址找到相关的域,并扩大我们的威胁情报图片。这些额外的域在逻辑上必须嵌入一些我们无法直接访问的样本中。例如,我们发现的一个地址是 ,它未解析到以下IcedID域:

152[.]89.247.60

formgotobig[.]top
ponduroviga[.]top
tranmigrust[.]club
aswenedo[.]space

总结


一个可悲的事实是,做 "正确的事情 "可能会适得其反。IcedID活动的维护者就是这种情况;他们制作了一个自签名的证书,并让他们的恶意操作支持HTTPS,这是一个值得称赞的努力,绝大多数恶意软件都不屑一顾,甚至一些长期运行的合法网站在很长一段时间内也不屑一顾。通过这样做,他们使煽动敌意接管他们的网络变得更具挑战性--但他们也使他们所有的服务器基本上以欢快的 "嗨,我是一个恶意的C&C "来回应标准扫描服务。


一旦这些服务器被暴露,我们就能持续追踪它们,分析它们的行为,而不需要运行正则表达式,更不用说启动调试器或反汇编器。对于运行恶意活动的人来说,这是一个噩梦般的场景;他们的目的是将不断更新的C&C服务器列表中的 "奖品 "放在遥不可及的地方,放在层级列表的顶端。相反,由于这种太过聪明的TLS业务,收集服务器(并获得一堆多汁的信息,这不在本文的范围之内)变得在分析师的能力范围之内,只要有一周的经验。正如一位智者曾经说过的,在使用一种技术之前要先思考,否则你的对手会用它来对付你。 

IOC

IcedID C&C servers:

83[.]97.20.249
83[.]97.20.174
194[.]5.249.52
45[.]153.240.135
194[.]5.250.104
152[.]89.247.60
91[.]193.19.97
194[.]5.249.81
83[.]97.20.73
194[.]5.250.35
83[.]97.20.176
194[.]5.250.46
212[.]114.52.186
91[.]193.19.37
45[.]147.231.113
188[.]119.148.75
185[.]38.185.90
45[.]138.172.179
91[.]193.19.51
83[.]97.20.122
194[.]5.249.103
139[.]60.161.63
194[.]5.249.86
139[.]60.161.48
185[.]33.85.35
194[.]5.249.97
79[.]141.164.241
194[.]5.249.90
193[.]109.69.52
194[.]5.249.54
185[.]70.184.87
79[.]141.166.39
146[.]0.77.92
31[.]184.199.11
45[.]129.99.241
194[.]5.249.46
185[.]123.53.202
146[.]0.77.18
31[.]24.228.170
45[.]147.230.88
83[.]97.20.254
45[.]147.230.82
194[.]5.249.72
46[.]17.98.191
45[.]153.241.115
185[.]70.184.41
139[.]60.161.50
194[.]5.249.143
79[.]141.161.176
5[.]149.252.179
45[.]147.228.198
91[.]193.19.251

附录A

测试一个服务器的IcedID证书:

import idna
 
from socket import socket
from OpenSSL import SSL
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat
 
def fnv1a_32(data: bytes) -> int:
    """Fowler–Noll–Vo hash function variation.
 
    Args:
        data (bytes): Input data
 
    Returns:
        int: Output 32 bit hash
    """
    hval_init = 0x811c9dc5
    fnv_prime = 0x01000193
    fnv_size = 2 ** 32
 
    hval = hval_init
    for byte in data:
        hval = hval ^ byte
        hval = (hval * fnv_prime) % fnv_size
    return hval
 
def get_certificate(hostname: str, port: int):
    """Connects to the remote server,
    and retrieves the certificate.
 
    Args:
        hostname (str): Remote hostname
        port (int): Remote port (usually 443)
 
    Returns: 
        Certificate object
    """
    hostname_idna = idna.encode(hostname)
 
    # We are building a SSL context on top of a raw socket.
    sock = socket()
    sock.connect((hostname, port))
    ctx = SSL.Context(SSL.SSLv23_METHOD)
    ctx.check_hostname = False
    # the cert is self-signed so we don't want to verify it
    ctx.verify_mode = SSL.VERIFY_NONE
 
    # making SSL handshake
    sock_ssl = SSL.Connection(ctx, sock)
    sock_ssl.set_connect_state()
    sock_ssl.set_tlsext_host_name(hostname_idna)
    sock_ssl.do_handshake()
 
    # retrieving certificate and converting it to an cryptography object
    cert = sock_ssl.get_peer_certificate()
    crypto_cert = cert.to_cryptography()
    sock_ssl.close()
    sock.close()
 
    return crypto_cert
 
def test_is_icedid_c2(hostname: str, port: int) -> bool:
    """Testing whether a remote server is part of IcedID
    C&C infrastructure.
 
    Args:
        hostname (str): Remote hostname
        port (int): Remote port (usually 443)
 
    Returns:
        bool: True if the server is IcedID verified, or False otherwise.
    """
    try:
        # We query the server and retrieve its certificate.
        cert = get_certificate(hostname, port)
        serial_number = cert.serial_number
 
        # Getting the public key, and hashing it.
        public_key = cert.public_key().public_bytes(Encoding.DER, PublicFormat.PKCS1)
        fnv_hash = fnv1a_32(public_key) & 0x7fffffff
 
        # Finally comparing the hash to the serial number.
        if serial_number == fnv_hash or serial_number == fnv_hash ^ 0x384A2414:
            return True
    except Exception as e:
        return False
    return False



[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

最后于 2021-6-1 17:58 被梦幻的彼岸编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回