OpenBMC 2.8 security audit results

Joseph Reynolds jrey at linux.ibm.com
Sat Jun 20 11:26:43 AEST 2020


Here are the results from my "security audit" on the planned OpenBMC 2.8 
release.  The results are not intended as a complete analysis, but only 
offer highlights into the BMC's security configuration. Contributions 
are appreciated.
The script to perform these tests was presented here: 
https://lists.ozlabs.org/pipermail/openbmc/2020-April/021186.html and 
was followed more-or-less.

- Joseph

__________

The image under test was built from 2.8.0-rc1 and necessarily customized 
for its target machine.
This customization may change some behaviors away from project defaults.
The BMC had its out of box setup, with the password as 0penBmc.
The bmcweb HTTPS certificate was the self-signed cert generated by BMCWeb.
Commands were run one-by-one, and results cut&pasted; any errors in that 
process are mine.
Not all results are shown here.  Some of the results contain sensitive 
data; these are removed and marked as REDACTED.

$ echo "Collecting test host basic data"
$ echo "Checking test host openssl version"
Checking test host openssl version
$ openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

$ echo "Testing: Ping the BMC"
observed: ping works

$ echo "Testing: Check for mDNS discovery service"
$ avahi-browse --all --ignore-local --resolve --terminate
note: the avahi client was not available
result: did not test the BMC's discovery service

$ echo "Testing: network (out of band) IPMI"
$ ipmitool_args="-H ${bmc} -I lanplus -C 17 -U ${bmcadminuser} -P 
${bmcadminpassword}"
note: parameter is newly required `-C 17` because cipher suite 3 was removed

$ echo "Testing: List IPMI users"
$ ipmitool ${ipmitool_args} user list 1
ID  Name         Callin  Link Auth    IPMI Msg   Channel Priv Limit
1   root             false   true       true       ADMINISTRATOR
2   readonly         false   true       true       USER
3                    true    false      false      NO ACCESS
4                    true    false      false      NO ACCESS
5                    true    false      false      NO ACCESS
6                    true    false      false      NO ACCESS
7                    true    false      false      NO ACCESS
8                    true    false      false      NO ACCESS
9                    true    false      false      NO ACCESS
10                   true    false      false      NO ACCESS
11                   true    false      false      NO ACCESS
12                   true    false      false      NO ACCESS
13                   true    false      false      NO ACCESS
14                   true    false      false      NO ACCESS
15                   true    false      false      NO ACCESS

interpretation: The default root admin user and an additional readonly 
user are configured.

$ echo "Testing: Print IPMI network settings"
Testing: Print IPMI network settings
$ ipmitool ${ipmitool_args} lan print 1
Set in Progress         : Set Complete
Auth Type Support       :
Auth Type Enable        : Callback :
                         : User     :
                         : Operator :
                         : Admin    :
                         : OEM      :
IP Address Source       : Static Address
IP Address              : REDACTED
Subnet Mask             : REDACTED
MAC Address             : REDACTED
Default Gateway IP      : REDACTED
Default Gateway MAC     : 00:00:00:00:00:00
802.1q VLAN ID          : Disabled
RMCP+ Cipher Suites     : 17
Cipher Suite Priv Max   : aaaaaaaaaaaaaaa
                         :     X=Cipher Suite Unused
                         :     c=CALLBACK
                         :     u=USER
                         :     o=OPERATOR
                         :     a=ADMIN
                         :     O=OEM
Bad Password Threshold  : Not Available

observation: Only suite 17 is available; that is as intended

$ echo "Testing: Show IPMI supported cipher suites"
Testing: Show IPMI supported cipher suites
$ ipmitool ${ipmitool_args} channel getciphers ipmi 0x1
ID   IANA    Auth Alg        Integrity Alg   Confidentiality Alg
17   N/A     hmac_sha256     sha256_128      aes_cbc_128
$ ipmitool ${ipmitool_args} channel getciphers sol 0x1
ID   IANA    Auth Alg        Integrity Alg   Confidentiality Alg
17   N/A     hmac_sha256     sha256_128      aes_cbc_128


Access to the BMC via SSH

jrey at gfwa180:~ $ echo "Testing: security aspects of the SSH connection"
Testing: security aspects of the SSH connection
$ ssh -p ${bmcsshport} -vv ${bmcadminuser}@${bmc} echo "Hello OpenBMC"
OpenSSH_7.8p1, OpenSSL 1.0.1u  22 Sep 2016
...excerpted...snip...
debug1: Local version string SSH-2.0-OpenSSH_7.8
debug1: Remote protocol version 2.0, remote software version 
dropbear_2019.78
...snip...
debug2: peer server KEXINIT proposal
debug2: KEX algorithms: 
curve25519-sha256,curve25519-sha256 at libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha256,kexguess2 at matt.ucc.asn.au
debug2: host key algorithms: ssh-rsa
debug2: ciphers ctos: aes128-ctr,aes256-ctr
debug2: ciphers stoc: aes128-ctr,aes256-ctr
debug2: MACs ctos: hmac-sha1,hmac-sha2-256
debug2: MACs stoc: hmac-sha1,hmac-sha2-256
debug2: compression ctos: zlib at openssh.com,none
debug2: compression stoc: zlib at openssh.com,none
...snip...

observation: The BMC offers its exact SSH server version.  That is not 
recommended.
observation: The BMC SSH server offers the algorithms shown above. 
Should we remove HMAC-SHA1?

$ echo "Testing: SSH SoL connection (port 2200)"
jrey at gfwa180:~ $ timeout 20s ssh -p 2200 ${bmcadminuser}@${bmc}
root at REDACTED's password:   <-- entered correct password for BMC root 
account
result: Access was granted when the correct BMC root account password 
was used.
result: Access was denied when an incorrect BMC root account password 
was used.

$ echo "Testing: HTTP response headers"
Testing: HTTP response headers
$ curl -k -D ${workdir}/http-response-headers -X GET 
https://${bmc}/redfish/v1
...the HTTP response body is not shown...
jrey at gfwa180:~ $ cat ${workdir}/http-response-headers
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=31536000; includeSubdomains; preload
X-Frame-Options: DENY
Pragma: no-cache
Cache-Control: no-Store,no-Cache
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'none'; img-src 'self' data:; 
font-src 'self'; style-src 'self'; script-src 'self'; connect-src 'self' 
wss:
Content-Type: application/json
Server: iBMC
Date: Fri, 19 Jun 2020 22:00:00 GMT
Content-Length: 1050

observation: the http response appear correct per 
https://github.com/openbmc/bmcweb/blob/master/include/security_headers_middleware.hpp

$ curl -k -v --tlsv1.1 -X GET https://${bmc}/redfish
* About to connect() to 9.41.167.159 port 443 (#0)
*   Trying 9.41.167.159...
* Connected to 9.41.167.159 (9.41.167.159) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
* NSS error -12190 (SSL_ERROR_PROTOCOL_VERSION_ALERT)
* Peer reports incompatible or unsupported protocol version.
* Closing connection 0
curl: (35) Peer reports incompatible or unsupported protocol version.

observation: TLSv1.1 is disabled as intended

$ curl -k --tlsv1.2 -X GET https://${bmc}/redfish
{
   "v1": "/redfish/v1/"
}

observation: TLSv1.2 works as intended

echo "Testing: SSL renegotiation"
$ openssl s_client -connect ${bmc}:443
CONNECTED(00000003)
...snip...
---
R
RENEGOTIATING
140737353955216:error:14094153:SSL routines:ssl3_read_bytes:no 
renegotiation:s3_pkt.c:1481:

observation: Requesting renegotiation (the "R" above) failed.  See 
https://github.com/openbmc/openbmc/issues/3624

# This probes unauthenticated REST API access
$ curl -k -X GET https://${bmc}/ | gunzip
<!doctype html><html ng-app="app" ng-csp lang="en"><head><meta 
http-equiv="Content-Security-Policy"><meta 
charset="UTF-8"><title>OpenBMC</title><meta name="viewport" 
content="width=device-width,initial-scale=1"><base href="/"><link 
rel="shortcut icon" href="/favicon.ico"><link href="/app.css" 
rel="stylesheet"></head><body ng-style="dataService.bodyStyle" 
ng-attr-id="{{!dataService.showNavigation ? 'login': ''}}"><app-header 
ng-if="dataService.showNavigation" 
path="dataService.path"></app-header><app-navigation 
ng-if="dataService.showNavigation" path="dataService.path" 
show-navigation="dataService.showNavigation"></app-navigation><toast 
ng-if="dataService.showNavigation"></toast><main ng-view 
ng-class="{'content__container': dataService.showNavigation, 
'login__wrapper': !dataService.showNavigation}"></main><script 
src="/app.bundle.js"></script></body></html>

curl -k -X GET https://${bmc}/redfish/
curl -k -X GET https://${bmc}/redfish/v1/
curl -k -X GET https://${bmc}/redfish/v1/JsonSchemas
note: results omitted

observation: Unauthenticated access to the URIs shown above is allowed, 
as intended

$ curl -k -X GET https://${bmc}/redfish/v1/Registries
Unauthorized
$ curl -k -X GET https://${bmc}/redfish/v1/SessionService
Unauthorized
$ curl -k -X GET https://${bmc}/redfish/v1/SessionService/Sessions
Unauthorized
$ curl -k -X GET https://${bmc}/redfish/v1/AccountService
Unauthorized
$ curl -k -X GET https://${bmc}/redfish/v1/AccountService/Accounts
Unauthorized

observation: Unauthenticated access to the URIs shown above is rejected, 
as intended

# Probe BMC security settings via Administrator REST API access
: First create a login session:
$ curl --insecure -X POST -D headers.txt \
 > https://${bmc}:${bmc_https_port}/redfish/v1/SessionService/Sessions \
 >      -d '{"UserName":"'${bmcadminuser}'", 
"Password":"'${bmcadminpassword}'"}' | tee ${workdir}/results.txt
{
   "@odata.id": "/redfish/v1/SessionService/Sessions/lwpuEVQ1th",
   "@odata.type": "#Session.v1_0_2.Session",
   "Description": "Manager User Session",
   "Id": "REDACTED",
   "Name": "User Session",
   "UserName": "root"
}
$ authtok=$(grep "^X-Auth-Token: " headers.txt | cut -d' ' -f2 | tr -d '\r')
$ test -n "${authtok}" && echo "Got X-Auth-Token okay (in shell variable 
authtok)" || { echo "Failed to get X-Auth-Token" && false; }
Got X-Auth-Token okay (in shell variable authtok)
$ sessid=$(grep -e '"Id":' ${workdir}/results.txt | cut -d\" -f4)

$ curl -k -H "X-Auth-Token: ${authtok}" -X GET 
https://${bmc}/redfish/v1/AccountService
{
   "@odata.id": "/redfish/v1/AccountService",
   "@odata.type": "#AccountService.v1_5_0.AccountService",
   "AccountLockoutDuration": 300,
   "AccountLockoutThreshold": 5,
   "Accounts": {
     "@odata.id": "/redfish/v1/AccountService/Accounts"
   },
   "MaxPasswordLength": 20,
   "MinPasswordLength": 7,
   "Name": "Account Service",
   "Oem": {
     "OpenBMC": {
       "@odata.type": "#OemAccountService.v1_0_0.AccountService",
       "AuthMethods": {
         "BasicAuth": true,
         "Cookie": true,
         "SessionToken": true,
         "TLS": false,
         "XToken": true
       }
     }
   },
   "ServiceEnabled": true
   ...snip...not all fields are shown...
}

note: The AccountLockoutDuration and AccountLockoutThreshold values used 
for this test may be customized differently than the base OpenBMC 
image.  They appear correct.
observation: the value for MinPasswordLength does not seem to match the 
content of the BMC's Linux-PAM config file /etc/pam.d/common-password.  
This should be investigated.


Probe BMC settings when logged in as root

# cat /etc/os-release
ID=openbmc-witherspoon
NAME="Phosphor OpenBMC (Phosphor OpenBMC Project Reference Distro)"
VERSION="2.8.0-rc1"
VERSION_ID=2.8.0-rc1-0-g35a774200
PRETTY_NAME="Phosphor OpenBMC (Phosphor OpenBMC Project Reference 
Distro) 2.8.0-rc1"
BUILD_ID="2.8.0-rc1"
...snip...

The intended release appears to appears to be installed on the BMC.

# cat /etc/shadow
root:$6$REDACTED:18425:0:99999:7:::
...snip...
readonly:$6$REDACTED:18431:0:99999:7:::

A user account called "readonly" is present.

# groups root
priv-admin web redfish ipmi root

note: This denotes the root user has Privilege Role "admin" and Group 
Roles as shown; these appear correct modulo 
https://github.com/openbmc/openbmc/issues/3643


observed: User account "readonly" cannot authenticate via ssh (because 
that requires the Administrator role).

observed: User "testuser" with Role=Administrator can authenticate via SSH.

When logged into the BMC via SSH as testuser:
testuser$ ls -la /home/root
drwxr-xr-x    2 root     root           384 Jun 18 00:00 .
drwxr-xr-x    5 root     root           368 Jun 20 00:23 ..
-rw-------    1 root     root         12437 Jun 20 00:24 .bash_history
-rw-r-----    1 root     root           459 Jun 19 20:19 
bmcweb_persistent_data.json

observation: Non-root user can list files in /home/root; that seems 
undesireable.  The files themselves are not readable.

testuser$ ls -l /etc
...snip...
-rw-r--r--    1 root     root           898 Jun 20 00:23 group
...snip...
-rw-------    1 root     root           208 Jun 20 00:23 ipmi_pass
...snip...
-rw-------    1 root     root             9 May 26 19:30 key_file
...snip...
drwxr-xr-x    1 root     root           248 Jun 19 22:42 pam.d
-rw-r--r--    1 root     root          1164 Jun 20 00:23 passwd
...snip...
-r--------    1 root     root          1070 Jun 20 00:23 shadow
...snip...

observation: Files in /etc seem to be protected properly.  See 
CVE-2020-14156 here: https://github.com/openbmc/openbmc/issues/3670

testuser$ ls -lR /etc/ssl
/etc/ssl:
drwxr-xr-x    4 root     root           296 Jun 10 06:22 certs
-rw-r--r--    1 root     root         10909 May 26 18:48 openssl.cnf

/etc/ssl/certs:
drwx------    2 root     root           160 Jun 10 06:22 authority
drwx------    2 root     root           304 Jun 10 06:23 https

observation: Certificates under /etc/ssl are protected from reading



More information about the openbmc mailing list