PART 1
点击上方蓝字关注我们
摘要
OpenSSH中的XZ后门除了具备异常复杂的功能, 还引入了一些高超的技术,例如:利用x86隐写术提取ED448加密公钥、自创密钥重建算法、挂钩RSA函数、防重放攻击技术、绕过SSH身份验证、日志隐藏技术等。但最牛的还是作者的社会工程学技术, 将这些技术揉合在一起, 对供应链安全造成了非常巨大的威胁。
分析主要发现
XZ后门采用了一些比较特别的技术,主要包括以下几个部分:
-
攻击者设置了防重放功能,以避免可能捕获或劫持后门通信。
-
后门作者在x86代码中使用了自定义的隐写技术来隐藏公钥, 这是一种非常巧妙的隐藏公钥的技术。
-
该后门通过挂钩日志功能来隐藏与 SSH 服务器的未经授权连接的日志。
-
该后门挂钩密码验证功能,允许攻击者使用任何用户名/密码登录受感染的服务器,而无需进行任何进一步的检查。它对于公钥身份验证也执行相同的操作。
-
它具有远程代码执行功能,允许攻击者在受感染的服务器上执行任何系统命令。
Hook技术详细分析
后门尝试挂钩三个函数,其中 RSA_public_decrypt 是主要目标,RSA_get0_key 是次要目标。第三个函数 EVP_PKEY_set1_RSA 在相关 SSH 服务器版本中不存在。它可能是用于恶意公钥生成的工具留下的组件(该功能由 OpenSSH 数据包中包含的独立 ssh-keygen 工具使用),或者它可能已在过时的 SSH 版本中使用服务器。
当RSA证书配置为SSH认证方式时,会调用最新SSH服务器版本中的两个目标函数。它们首先检查传入的 RSA 连接是否使用身份验证数据(RSA 密钥)作为参数。如果是,后门会将其传递给一个公共函数(由所有挂钩调用),该函数解析此 RSA 密钥并提取嵌入其模数部分的信息。后门的主要有效负载功能仅在客户端预身份验证会话期间(即执行基于 RSA 的身份验证检查时)工作一次。RSA_public_decrypt钩子函数如下图:
攻击者必须生成特定的 RSA 密钥才能与后门服务器进行交互;该密钥用作使用 CA 证书的 SSH 连接中攻击者命令的容器。
RSA 密钥由 OpenSSL 库中包含 E(指数)和 N(模数)的结构表示。后门提取并处理 RSA 模数,这意味着恶意Payload被打包在 RSA 密码系统的 N 值内。
自定义的RSA模数必须符合以下格式才能被后门正确处理, RSA模数数据结构如下图:
如果计算的检查通过,代码将继续进行有效Payload解密和有效负载签名检查。
基于x86的隐写术-ED448加密公钥提取
为了解密和验证有效Payload数据,后门使用从二进制文件中提取的 ED448 公钥。
当第一次遇到密钥提取过程时,后门作者似乎已设法创建在私钥之前生成正确公钥的代码,这应该是不可能的。通常,对于椭圆曲线算法,必须先生成私钥,然后根据私钥计算公钥。为了解开从二进制文件生成公钥的谜团,我们分析了各种密码库的源代码,但一无所获。然后我们更仔细地分析了后门代码,发现密钥是使用常规程序生成的。然而,攻击者在 x86 代码中使用了自定义隐写技术来隐藏任意消息(在本例中为公钥)。
公钥信息分散在特定有效指令内的二进制代码内。恢复密钥的方法有点类似于面向返回编程(ROP)二进制利用场景中的小工具扫描技术。但这里的“gadgets”实际上是寄存器-寄存器指令(例如,mov rdi、rbx),每个指令都保存一位信息,其值为 1 或 0。
为了实现密钥恢复,某些函数(通常在函数的开头)使用特定参数调用“密钥重建”算法。部分密钥重建函数调用如下图:
该算法使用的参数为:
-
BitIndex:起始值,保存当前要解码的密钥索引,还保存加密密钥位图中最初应设置的位。
-
Total Instructions:当前函数中要扫描的寄存器-寄存器指令的数量。
-
Key Index: 该函数将重建的特定键索引。该值的存在是为了避免在第二次调用同一函数时重新扫描该函数。
下图是寄存器指令译码的片段:
密钥重建算法从头到尾扫描后门的某些函数,寻找寄存器-寄存器指令。当它找到指令时,它会解码“BitIndex”值以提取正确的字节索引和要设置的位。下图是加密密钥重建代码片段:
BitIndex 值被解包以确定缓冲区中的目标索引。然后,它将该位添加(按位或)到该索引处的当前值。由于加密的公钥缓冲区是用零初始化的,因此重建器算法将仅激活其中的特定位。如果寄存器-寄存器指令匹配操作码标准(上图),它将关键位值设置为 1,或者跳过它,指示该位值应保持为零。之后,BitIndex 值增加。
该算法确定是否应单独为每条指令设置该位,即使这些指令具有相同的反汇编表示。这是因为某些指令可以具有相同的汇编代码但不同的操作码。
下图为公钥重建算法:
一般来说,对于找到的每条指令,BitIndex 用于重建加密密钥的特定部分。通过二进制执行总共搜索了 456 条指令,并在此过程结束时重建加密的公钥。
在我们的研究中, 重新还原了整个密钥重建过程,该过程产生了随后解密的加密公钥, 如图:
Payload解密和签名检查
ED448公钥使用ChaCha20算法进行加密,其中密钥和随机数是ChaCha20对由零组成的缓冲区进行加密的结果,其中零用作密钥和随机数。解密后,后门获取公钥的前 32 个字节,并将其用作解密有效Payload正文的密钥,该有效Payload正文也是经过 ChaCha20 加密的。下图是后门payload解密及检查流程:
解密的有效Payload在其标头中包含剩余数据的签名。要验证签名,必须拥有私钥来对有效Payload进行签名。在预期的攻击场景中,只有后门作者有权签名并将有效Payload发送到受感染的服务器。
为了验证有效负载的完整性和真实性,后门再次使用解密的 ED448 公钥来确认传入的有效负载是使用攻击者的私钥签名的。有效Payload完整性和真实性检查代码如下图:
它还将服务器公钥的 SHA-256 哈希值(在服务器发送公钥时从初始 SSH 连接获取)放入有效Payload签名数据中,并验证它是否与当前运行的服务器匹配。这样做是为了防止重放攻击,研究人员可以捕获后门通信并将相同的后门命令重放到另一台服务器。以下是抗重放攻击图:
如果所有检查都通过,代码将继续解析所需后门命令的参数。后门可以以 root 和非 root 两种模式执行命令,并且执行情况会根据权限级别的不同而有所不同。然而,非 root 模式操作似乎并不是攻击者的目标,因此我们将描述 root 模式代码的作用。
后门命令
攻击者选择的命令取决于头字段的计算结果。核心后门命令本质上允许攻击者以 root 或普通用户身份登录服务器并执行一些系统命令。本节描述每个命令的作用。
(1). 绕过SSH身份验证
如果之前未启用,命令 0 和 1 都会在 SSH 服务器上启用 root 登录。此外,他们可以选择禁用可插入身份验证模块 (PAM) 的使用。接下来,根据命令,可以挂钩两个 OpenSSH 函数之一,如果命令为 1,则为 mm_answer_authpassword;如果命令为 0,则为 mm_answer_keyallowed。下图是第一个命令的核心代码:
mm_answer_authpassword 挂钩允许攻击者使用任何用户名/密码登录受感染的服务器,而无需进行任何进一步检查。
(2).通过系统调用远程执行命令
如果命令为2,则它从有效Payload数据中提取命令字符串,并使用系统函数在机器上执行它。攻击者可以在有效Payload正文中发送特定标志来指定应在其下执行命令的用户和组 ID。以下是远程命令执行代码片段:
最后一个后门命令 (3) 只是通过退出 Monitor 进程来关闭预身份验证会话。主钩子函数完成后,后门会将传入的 RSA 公钥替换为空公钥,以避免记录来自攻击者的任何恶意数据。
(3).mm_answer_keyallowed挂钩
如果后门命令为 0,则 mm_answer_keyallowed 函数将被挂钩。当非特权 NetworkProcessing sshd 进程收到 ssh-userauth 请求的 publickey 方法时,特权 Monitor 进程会调用此函数,从而允许后门在该阶段处理其他命令。
在该处理方法中,会发生类似的步骤:提取、解密附加到 ssh-userauth 请求 RSA 密钥的模数,并检查其签名,如前所述。可能的子命令有:
-
子命令1: 挂钩 mm_answer_authpassword 函数以允许用户使用任何密码登录请求。
-
子命令2: 挂钩 mm_answer_keyverify 函数以允许使用假密钥进行身份验证,并将收到的后门命令存储在内部结构中。mm_answer_keyverify 挂钩本质上允许传入密钥通过身份验证过程而无需进一步检查,从而使用假密钥成功完成授权。
-
子命令3: 与系统执行方法类似,该命令允许使用系统功能执行命令,并可以选择组/用户 ID。
日志隐藏功能
后门还可以通过挂钩日志记录功能并选择性地调用 libc setlogmask(0x80000000) 来隐藏指示与 SSH 服务器的未经授权连接的日志,这会导致所有 Syslog 消息被忽略。参数中的0x80000000实际上意味着将日志掩码设置为零,因为零掩码参数是一个具有特殊含义的保留值。
该钩子还将通过在前缀树中搜索日志消息来过滤日志消息,其进一步的行为取决于找到的目标消息(如果有), 以下是日志过滤代码片段:
可能的日志过滤器有:
-
Connection closed by – 暂时将 libc 的系统日志掩码恢复为其默认值 255,允许之前清除的所有系统日志消息,并允许记录此消息。通过清除日志掩码再次禁用系统日志消息
-
“Accepted password for ”和 “Accepted publickey for “ – 将这些成功的连接消息替换为有关失败的身份验证尝试的消息。如果之前已清除,还可以暂时启用然后禁用系统日志掩码。
-
All other log messages – 过滤掉(不打印)
总结
XZ后门确实是一个高度复杂的威胁,具有许多特点。几个亮点使这种威胁独一无二,例如公钥信息嵌入二进制代码本身的方式、恢复过程的复杂性以及操作的精心准备,其中涉及长期的社会工程活动。
值得注意的是,这种威胁背后的组织或攻击者对 SSH 和 libc 等开源项目的内部结构有着广泛的了解,并且拥有用于启动感染的代码/脚本混淆方面的专业知识。
原文地址:https://securelist.com/xz-backdoor-part-3-hooking-ssh/113007/
点个在看你最好看
东 WHAT HAPPENED IN MAY 西
原文始发于微信公众号(二进制空间安全):OpenSSH中XZ后门的牛X Hook技术分析