本文为译文,原文配图参见原文(原文链接见文末)
2024年6月25日 8分钟阅读时间
作者
ANDERSON LEITE
SERGEY BELOV
在我们关于XZ后门的第一篇文章中,我们分析了从初始感染到它执行函数Hook的代码。正如我们当时提到的,它的最初目标是成功Hook与RSA密钥操作相关的函数之一。在本文中,我们将重点关注后门在OpenSSH中的行为,具体是OpenSSH Portable 9.7p1版本 – 目前最新的版本。
为了更好地理解发生了什么,我们建议您阅读Baeldung关于SSH身份验证方法的文章以及JFrog关于SSH中特权分离的文章。
我们的分析揭示了有关后门功能的以下有趣细节:
攻击者设置了反重放功能,以避免可能捕获或劫持后门通信。
后门作者在x86代码中使用自定义隐写术隐藏公钥,这是一种非常聪明的隐藏公钥的技术。
后门通过Hook日志记录函数隐藏其对SSH服务器的未经授权的连接日志。
后门Hook密码身份验证函数,允许攻击者使用任何用户名/密码登录受感染的服务器,无需任何进一步检查。它对公钥身份验证也执行相同的操作。
它具有远程代码执行功能,允许攻击者在受感染的服务器上执行任何系统命令。
后门试图Hook三个函数,其中RSA_public_decrypt是主要目标,RSA_get0_key是次要目标。第三个函数EVP_PKEY_set1_RSA在所讨论的SSH服务器版本中不存在。它可能是用于恶意公钥生成的工具遗留下来的产物(OpenSSH数据包中包含的独立ssh-keygen工具使用此函数),或者它可能已在罕见或过时的SSH服务器版本中使用。
在最新的SSH服务器版本中,当RSA证书配置为SSH身份验证方法时,会调用两个目标函数。它们首先检查传入的RSA连接是否使用身份验证数据(RSA密钥)作为参数。如果是,后门会将其传递给公共函数(由所有Hook调用),该函数解析此RSA密钥并提取嵌入在其模数部分中的信息。后门的主要有效负载函数仅在客户端预认证会话期间工作一次,当执行基于RSA的身份验证检查时。
攻击者必须生成特定的RSA密钥才能与植入后门的服务器交互;该密钥在使用CA证书的SSH连接中用作攻击者命令的容器。
RSA密钥由OpenSSL库中的结构表示,其中包含E(指数)和N(模数)。后门提取并处理RSA模数,这意味着恶意负载被打包在来自RSA密码系统的N值内。
自定义RSA模数必须符合以下格式,才能被后门正确处理:
有效载荷头中有三个字段(上图中的PartialCommand1、2和3),用于计算命令类型,并充当一种魔术数字检查形式。使用以下公式计算命令类型:PartialCommand3 + (PartialCommand2 * PartialCommand1),其中计算结果必须是0到3之间的值:
如果计算检查通过,代码将继续进行有效负载解密和有效负载签名检查。
为了解密和验证有效负载数据,后门使用从二进制文件中提取的ED448公钥。
当我们第一次遇到密钥提取过程时,看起来后门作者已经设法创建了在私钥之前生成正确公钥的代码,这应该是不可能的。通常,对于椭圆曲线算法,必须首先生成私钥,然后从私钥计算公钥。为了解开从二进制文件生成公钥的谜团,我们分析了各种加密库的源代码,但一无所获。然后,我们更仔细地分析了后门代码,发现密钥是使用常规过程生成的。但是,攻击者在x86代码中使用自定义隐写术隐藏任意消息(在本例中为公钥)。
公钥信息散布在二进制代码的特定有效指令中。恢复密钥的方法有点类似于面向返回编程(ROP)二进制漏洞利用场景中的小工具扫描技术。但是这里的"小工具"实际上是寄存器-寄存器指令(例如,mov rdi, rbx),每个指令都包含一位信息,其值为1或0。
为了实现密钥恢复,一些函数(通常在函数开始时)使用特定参数调用"密钥重建"算法。
此算法使用的参数是:
BitIndex:保存要解码的当前密钥索引的起始值,并保存应在加密密钥位图中初始设置哪个位。
Total Instructions:当前函数中要扫描的寄存器-寄存器指令数。
Key Index:此函数将重建的特定密钥索引。此值存在是为了避免在第二次调用函数时重新扫描相同的函数。
密钥重建算法从头到尾扫描后门的某些函数,寻找寄存器-寄存器指令。当找到一条指令时,它解码"BitIndex"值以提取正确的字节索引和要设置的位。
加密密钥重建代码片段
解包BitIndex值以确定缓冲区中的目标索引。然后,将位添加(按位或)到该索引处的当前值。由于加密的公钥缓冲区初始化为零,重建算法将仅激活其中的特定位。如果寄存器-寄存器指令与操作码条件匹配(上图),则将密钥位值设置为1,否则跳过它,表示该位值应保持为零。之后,BitIndex值增加。
该算法为每条指令单独确定是否应设置位,即使指令具有相同的反汇编表示也是如此。这是因为某些指令可能具有相同的汇编代码但不同的操作码。
总的来说,对于找到的每条指令,BitIndex用于重建加密密钥的特定部分。在整个二进制执行过程中,总共搜索了456条指令,在此过程结束时重建了加密的公钥。
在我们的研究中,我们重现了整个密钥重建过程,最终得到了加密的公钥,稍后将对其进行解密。
ED448公钥使用ChaCha20算法加密,其中密钥和nonce是由零组成的缓冲区的ChaCha20加密结果,使用零作为密钥和nonce。
解密后,后门取公钥的前32个字节,并使用它们作为密钥来解密也经过ChaCha20加密的有效负载主体。
解密的有效负载在其头部包含剩余数据的签名。要验证签名,必须有私钥来签署有效负载。在预期的攻击情况下,只有后门作者才能访问、签名并向受感染的服务器发送有效负载。
为了验证有效负载的完整性和真实性,后门再次使用解密的ED448公钥来确认传入的有效负载是用攻击者的私钥签名的。
它还将服务器公钥(从服务器发送公钥时的初始SSH连接中获取)的SHA-256哈希值纳入有效负载签名数据中,并验证它是否与当前运行的服务器相匹配。这样做是为了防止重放攻击,攻击者可能会捕获后门通信并将相同的后门命令重放到另一台服务器。
如果所有检查都通过,代码将继续解析所需后门命令的参数。后门可以在root和非root两种模式下执行命令,执行可能因权限级别而异。但是,非root模式操作似乎不是攻击者的目标,因此我们将描述root模式代码的作用。
攻击者选择的命令取决于对头字段的计算结果。核心后门命令基本上允许攻击者以root或普通用户身份登录服务器并执行一些系统命令。本节描述每个命令的作用。
命令0和1都可以在SSH服务器上启用root登录(如果之前未启用)。此外,它们可以选择禁用可插拔身份验证模块(PAM)的使用。接下来,根据命令,可以Hook两个OpenSSH函数之一,如果命令为1,则Hook mm_answer_authpassword,如果命令为0,则Hook mm_answer_keyallowed。
第一个命令核心代码
mm_answer_authpassword Hook允许攻击者使用任何用户名/密码登录受感染的服务器,而无需任何进一步检查。稍后我们将更详细地描述mm_answer_keyallowed。
如果命令是2,它会从有效负载数据中提取命令字符串,并使用system函数在计算机上执行它。攻击者可以在有效负载正文中发送特定标志,以指定应在其下执行命令的用户和组ID。
远程命令执行代码片段
最后一个后门命令(3)只是通过退出Monitor进程来关闭预认证会话。
主Hook函数完成后,后门会将传入的RSA公钥替换为空密钥,以避免记录来自攻击者的任何恶意数据。
如果后门命令为0,将Hook mm_answer_keyallowed函数。当非特权NetworkProcessing sshd进程接收到ssh-userauth请求的publickey方法时,特权Monitor进程调用此函数,允许后门在该阶段处理其他命令。
在此处理方法中,发生类似的步骤:提取附加到ssh-userauth请求的RSA密钥的模数,对其进行解密,并如前所述检查其签名。可能的子命令是:
子命令1: Hook mm_answer_authpassword函数,允许使用任何密码的用户登录请求。
子命令2: Hook mm_answer_keyverify函数,允许使用假密钥进行身份验证,并将接收到的后门命令存储在内部结构中。mm_answer_keyverify Hook实质上允许传入密钥通过身份验证过程,而无需进一步检查,从而使用假密钥成功完成授权。
子命令3: 与system执行方法类似,此命令允许使用system函数执行命令,并可选择组/用户ID。
后门还可以通过Hook日志记录函数并可选地调用libc setlogmask(0x80000000)来隐藏指示对SSH服务器的未经授权连接的日志,这会导致忽略所有Syslog消息。参数中的0x80000000实际上意味着将日志掩码设置为零,因为零掩码参数是具有特殊含义的保留值。
Hook还将通过在前缀树中搜索日志消息来过滤它们,如我们在第一篇关于XZ后门的文章中所述。其进一步行为取决于找到的目标消息(如果有):
日志过滤代码片段
可用的日志过滤器是:
日志消息 | 如何处理 |
---|---|
"Connection closed by" (连接被关闭) | 如果之前已清除日志掩码,则暂时将libc的syslog掩码恢复为默认值255,允许所有syslog消息,并允许记录此消息。如果之前已清除日志掩码,则再次通过清除日志掩码来禁用syslog消息 |
"Accepted password for" (接受密码) "Accepted publickey for" (接受公钥) | 将这些成功连接消息替换为有关身份验证尝试失败的消息。如果之前已清除日志掩码,还会暂时启用然后禁用syslog掩码。 |
所有其他日志消息 | 过滤掉(不打印) |
在发表了三篇关于这个后门的文章后,我们可以得出结论,它确实是一个非常复杂的威胁,具有许多特殊之处。几个亮点使这个威胁独一无二,例如将公钥信息嵌入二进制代码本身的方式,使恢复过程复杂化,以及对操作的精心准备,其中涉及一个长期运行的社会工程学攻击。
值得注意的是,这个威胁背后的团伙或攻击者对SSH和libc等开源项目的内部结构有广泛的了解,并且精通用于启动感染的代码/脚本混淆技术。
参考资料:
https://securelist.com/xz-backdoor-part-3-hooking-ssh/113007/
推荐阅读
闲谈
威胁情报
1.威胁情报 - 最危险的网络安全工作
2.威胁情报专栏 | 威胁情报这十年(前传)
3.网络威胁情报的未来
4.情报内生?| 利用威胁情报平台落地网空杀伤链的七种方法
5.威胁情报专栏 | 特别策划 - 网空杀伤链
APT
入侵分析与红队攻防
天御智库