macOS STIGs
CAT I 13
Any vulnerability, the exploitation of which will directly and immediately result in loss of confidentiality, availability or integrity.
-
The macOS system must limit SSHD to FIPS-compliant connections.
Maps to AC-17(2), IA-7, MA-4(6), SC-8(1), SC-13 via CCI-000068, CCI-000803, CCI-001453, CCI-002890, CCI-003123, CCI-002450, CCI-002421Check
Verify the macOS system is configured to limit SSHD to FIPS-compliant connections with the following command: fips_sshd_config=("Ciphers [email protected]" "HostbasedAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected]" "HostKeyAlgorithms [email protected],[email protected],ecdsa-sha2-nistp256,[email protected]" "KexAlgorithms ecdh-sha2-nistp256" "MACs [email protected],hmac-sha2-256" "PubkeyAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected],[email protected]" "CASignatureAlgorithms ecdsa-sha2-nistp256,[email protected]") total=0 for config in $fips_sshd_config; do total=$(expr $(/usr/sbin/sshd -G | /usr/bin/grep -i -c "$config") + $total) done echo $total If the result is not "7", this is a finding.
Fix
Configure the macOS system to limit SSHD to FIPS-compliant connections with the following command: if [ -f /etc/ssh/crypto.conf ] && /usr/bin/grep -q "Include /etc/ssh/crypto.conf" /etc/ssh/sshd_config.d/100-macos.conf 2>/dev/null; then /bin/ln -fs /etc/ssh/crypto/fips.conf /etc/ssh/crypto.conf fi include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/sshd_config | /usr/bin/tr -d '*') if [[ -z $include_dir ]]; then /usr/bin/sed -i.bk "1s/.*/Include \/etc\/ssh\/sshd_config.d\/\*/" /etc/ssh/sshd_config fi fips_sshd_config=("Ciphers [email protected]" "HostbasedAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected]" "HostKeyAlgorithms [email protected],[email protected],ecdsa-sha2-nistp256,[email protected]" "KexAlgorithms ecdh-sha2-nistp256" "MACs [email protected],hmac-sha2-256" "PubkeyAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected],[email protected]" "CASignatureAlgorithms ecdsa-sha2-nistp256,[email protected]") sshd_config=$(/usr/sbin/sshd -G) for config in $fips_sshd_config; do if ! echo $sshd_config | /usr/bin/grep -q -i "$config" 2>/dev/null; then /usr/bin/grep -qxF "$config" "${include_dir}01-mscp-sshd.conf" 2>/dev/null || echo "$config" >> "${include_dir}01-mscp-sshd.conf" fi done for file in $(ls ${include_dir}); do if [[ "$file" == "100-macos.conf" ]]; then continue fi if [[ "$file" == "01-mscp-sshd.conf" ]]; then break fi /bin/mv ${include_dir}${file} ${include_dir}20-${file} done
-
The macOS system must limit SSH to FIPS-compliant connections.
Maps to AC-17(2), IA-7, SC-8(1), SC-13 via CCI-000068, CCI-000803, CCI-001453, CCI-002450, CCI-002421Check
Verify the macOS system is configured to limit SSH to FIPS-compliant connections with the following command: fips_ssh_config=("Ciphers [email protected]" "HostbasedAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected]" "HostKeyAlgorithms [email protected],[email protected],ecdsa-sha2-nistp256,[email protected]" "KexAlgorithms ecdh-sha2-nistp256" "MACs [email protected],hmac-sha2-256" "PubkeyAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected],[email protected]" "CASignatureAlgorithms ecdsa-sha2-nistp256,[email protected]") total=0 ret="pass" for config in $fips_ssh_config; do if [[ "$ret" == "fail" ]]; then break fi for u in $(/usr/bin/dscl . list /users shell | /usr/bin/egrep -v '(^_)|(root)|(/usr/bin/false)' | /usr/bin/awk '{print $1}'); do sshCheck=$(/usr/bin/sudo -u $u /usr/bin/ssh -G . | /usr/bin/grep -ci "$config") if [[ "$sshCheck" == "0" ]]; then ret="fail" break fi done done echo $ret If the result is not "pass", this is a finding.
Fix
Configure the macOS system to limit SSH to FIPS-compliant connections with the following command: if [ -f /etc/ssh/crypto.conf ] && /usr/bin/grep -q "Include /etc/ssh/crypto.conf" /etc/ssh/ssh_config.d/100-macos.conf 2>/dev/null; then /bin/ln -fs /etc/ssh/crypto/fips.conf /etc/ssh/crypto.conf fi include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/ssh_config | /usr/bin/tr -d '*') fips_ssh_config=("Ciphers [email protected]" "HostbasedAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected]" "HostKeyAlgorithms [email protected],[email protected],ecdsa-sha2-nistp256,[email protected]" "KexAlgorithms ecdh-sha2-nistp256" "MACs [email protected],hmac-sha2-256" "PubkeyAcceptedAlgorithms ecdsa-sha2-nistp256,[email protected],[email protected]" "CASignatureAlgorithms ecdsa-sha2-nistp256,[email protected]") for ssh_config in $fips_ssh_config; do ssh_setting=$(echo $ssh_config | /usr/bin/cut -d " " -f1) /usr/bin/grep -qEi "^$ssh_setting" "${include_dir}01-mscp-ssh.conf" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/" "${include_dir}01-mscp-ssh.conf" || echo "$ssh_config" >> "${include_dir}01-mscp-ssh.conf" for u in $(/usr/bin/dscl . list /users shell | /usr/bin/egrep -v '(^_)|(root)|(/usr/bin/false)' | /usr/bin/awk '{print $1}'); do config=$(/usr/bin/sudo -u $u /usr/bin/ssh -Gv . 2>&1) configfiles=$(echo "$config" | /usr/bin/awk '/Reading configuration data/ {print $NF}'| /usr/bin/tr -d '\r') configarray=( ${(f)configfiles} ) if ! echo $config | /usr/bin/grep -q -i "$ssh_config" ; then for c in $configarray; do if [[ "$c" == "/etc/ssh/crypto.conf" ]]; then continue fi /usr/bin/sudo -u $u /usr/bin/grep -qEi "^$ssh_setting" "$c" && /usr/bin/sed -i "" "s/^$ssh_setting.*/${ssh_config}/I" "$c" if [[ "$c" =~ ".ssh/config" ]]; then if /usr/bin/grep -qEi "$ssh_setting" "$c" 2> /dev/null; then old_file=$(cat ~$u/.ssh/config) echo "$ssh_config" > ~$u/.ssh/config echo "$old_file" >> ~$u/.ssh/config fi fi done fi done done
-
The macOS system must disable password authentication for SSH.
Maps to IA-2(1), IA-2(2), IA-2(6), IA-2(8), IA-5(2), MA-4 via CCI-000186, CCI-000765, CCI-000766, CCI-001941, CCI-000877, CCI-004046Check
Verify the macOS system is configured to disable password authentication for SSH with the following command: /usr/sbin/sshd -G | /usr/bin/grep -Ec '^(passwordauthentication\s+no|kbdinteractiveauthentication\s+no)' If the result is not "2", this is a finding.
Fix
Configure the macOS system to disable password authentication for SSH with the following command: include_dir=$(/usr/bin/awk '/^Include/ {print $2}' /etc/ssh/sshd_config | /usr/bin/tr -d '*') if [[ -z $include_dir ]]; then /usr/bin/sed -i.bk "1s/.*/Include \/etc\/ssh\/sshd_config.d\/\*/" /etc/ssh/sshd_config fi echo "passwordauthentication no" >> "${include_dir}01-mscp-sshd.conf" echo "kbdinteractiveauthentication no" >> "${include_dir}01-mscp-sshd.conf" for file in $(ls ${include_dir}); do if [[ "$file" == "100-macos.conf" ]]; then continue fi if [[ "$file" == "01-mscp-sshd.conf" ]]; then break fi /bin/mv ${include_dir}${file} ${include_dir}20-${file} done
-
The macOS system must disable Trivial File Transfer Protocol (TFTP) service.
Check
Verify the macOS system is configured to disable TFTP service with the following command: result="FAIL" enabled=$(/bin/launchctl print-disabled system | /usr/bin/grep '"com.apple.tftpd" => enabled') running=$(/bin/launchctl print system/com.apple.tftpd 2>/dev/null) if [[ -z "$running" ]] && [[ -z "$enabled" ]]; then result="PASS" elif [[ -n "$running" ]]; then result=result+" RUNNING" elif [[ -n "$enabled" ]]; then result=result+" ENABLED" fi echo $result If the result is not "PASS", this is a finding.
Fix
Configure the macOS system to disable TFTP service with the following commands: /bin/launchctl bootout system/com.apple.tftpd /bin/launchctl disable system/com.apple.tftpd The system may need a restart for the update to take effect.
-
The macOS system must apply gatekeeper settings to block applications from unidentified developers.
Maps to CM-14 via CCI-003992Check
Verify the macOS system is configured to apply gatekeeper settings to block applications from unidentified developers with the following commands: /usr/bin/osascript -l JavaScript << EOS function run() { let pref1 = ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('com.apple.systempolicy.control')\ .objectForKey('AllowIdentifiedDevelopers')) let pref2 = ObjC.unwrap($.NSUserDefaults.alloc.initWithSuiteName('com.apple.systempolicy.control')\ .objectForKey('EnableAssessment')) if ( pref1 == true && pref2 == true ) { return("true") } else { return("false") } } EOS If the result is not "true", this is a finding.
Fix
Configure the macOS system to apply gatekeeper settings to block applications from unidentified developers by installing the "com.apple.systempolicy.control" configuration profile.
-
The macOS system must disable Bluetooth when no approved device is connected.
Maps to SC-8 via CCI-002418Check
Verify the macOS system is configured to disable Bluetooth with the following command: /usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.MCXBluetooth')\ .objectForKey('DisableBluetooth').js EOS If the result is not "true", this is a finding.
Fix
Configure the macOS system to disable Bluetooth by installing the "com.apple.MCXBluetooth" configuration profile.
-
The macOS system must enable gatekeeper.
Maps to CM-14 via CCI-003992Check
Verify the macOS system is configured to enable gatekeeper with the following command: /usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.systempolicy.control')\ .objectForKey('EnableAssessment').js EOS If the result is not "true", this is a finding.
Fix
Configure the macOS system to enable gatekeeper by installing the "com.apple.systempolicy.control" configuration profile.
-
The macOS system must disable unattended or automatic login to the system.
Check
Verify the macOS system is configured to disable unattended or automatic login to the system with the following command: /usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.loginwindow')\ .objectForKey('com.apple.login.mcx.DisableAutoLoginClient').js EOS If the result is not "true", this is a finding.
Fix
Configure the macOS system to disable unattended or automatic login to the system by installing the "com.apple.loginwindow" configuration profile.
-
The macOS system must require an administrator password to modify systemwide preferences.
Maps to AC-6(10) via CCI-002235Check
Verify the macOS system is configured to require administrator privileges to modify systemwide settings with the following command: authDBs=("system.preferences" "system.preferences.energysaver" "system.preferences.network" "system.preferences.printing" "system.preferences.sharing" "system.preferences.softwareupdate" "system.preferences.startupdisk" "system.preferences.timemachine") result="1" for section in ${authDBs[@]}; do if [[ $(/usr/bin/security -q authorizationdb read "$section" | /usr/bin/xmllint -xpath 'name(//*[contains(text(), "shared")]/following-sibling::*[1])' -) != "false" ]]; then result="0" fi if [[ $(security -q authorizationdb read "$section" | /usr/bin/xmllint -xpath '//*[contains(text(), "group")]/following-sibling::*[1]/text()' - ) != "admin" ]]; then result="0" fi if [[ $(/usr/bin/security -q authorizationdb read "$section" | /usr/bin/xmllint -xpath 'name(//*[contains(text(), "authenticate-user")]/following-sibling::*[1])' -) != "true" ]]; then result="0" fi if [[ $(/usr/bin/security -q authorizationdb read "$section" | /usr/bin/xmllint -xpath 'name(//*[contains(text(), "session-owner")]/following-sibling::*[1])' -) != "false" ]]; then result="0" fi done echo $result If the result is not "1", this is a finding.
Fix
Configure the macOS system to require administrator privileges to modify systemwide settings with the following command: authDBs=("system.preferences" "system.preferences.energysaver" "system.preferences.network" "system.preferences.printing" "system.preferences.sharing" "system.preferences.softwareupdate" "system.preferences.startupdisk" "system.preferences.timemachine") for section in ${authDBs[@]}; do /usr/bin/security -q authorizationdb read "$section" > "/tmp/$section.plist" class_key_value=$(usr/libexec/PlistBuddy -c "Print :class" "/tmp/$section.plist" 2>&1) if [[ "$class_key_value" == *"Does Not Exist"* ]]; then /usr/libexec/PlistBuddy -c "Add :class string user" "/tmp/$section.plist" else /usr/libexec/PlistBuddy -c "Set :class user" "/tmp/$section.plist" fi key_value=$(/usr/libexec/PlistBuddy -c "Print :shared" "/tmp/$section.plist" 2>&1) if [[ "$key_value" == *"Does Not Exist"* ]]; then /usr/libexec/PlistBuddy -c "Add :shared bool false" "/tmp/$section.plist" else /usr/libexec/PlistBuddy -c "Set :shared false" "/tmp/$section.plist" fi auth_user_key=$(/usr/libexec/PlistBuddy -c "Print :authenticate-user" "/tmp/$section.plist" 2>&1) if [[ "$auth_user_key" == *"Does Not Exist"* ]]; then /usr/libexec/PlistBuddy -c "Add :authenticate-user bool true" "/tmp/$section.plist" else /usr/libexec/PlistBuddy -c "Set :authenticate-user true" "/tmp/$section.plist" fi session_owner_key=$(/usr/libexec/PlistBuddy -c "Print :session-owner" "/tmp/$section.plist" 2>&1) if [[ "$session_owner_key" == *"Does Not Exist"* ]]; then /usr/libexec/PlistBuddy -c "Add :session-owner bool false" "/tmp/$section.plist" else /usr/libexec/PlistBuddy -c "Set :session-owner false" "/tmp/$section.plist" fi group_key=$(usr/libexec/PlistBuddy -c "Print :group" "/tmp/$section.plist" 2>&1) if [[ "$group_key" == *"Does Not Exist"* ]]; then /usr/libexec/PlistBuddy -c "Add :group string admin" "/tmp/$section.plist" else /usr/libexec/PlistBuddy -c "Set :group admin" "/tmp/$section.plist" fi /usr/bin/security -q authorizationdb write "$section" < "/tmp/$section.plist" done
-
The macOS system must ensure System Integrity Protection (SIP) is enabled.
Maps to AC-3, AU-6(4), AU-7, AU-7(1), AU-9, AU-9(3), AU-12, CM-5(6), SC-4 via CCI-000154, CCI-000158, CCI-000162, CCI-000163, CCI-000164, CCI-000169, CCI-000213, CCI-001876, CCI-001090, CCI-001493, CCI-001494, CCI-001495, CCI-001499, CCI-001496, CCI-001878Check
Verify the macOS system is configured to enable SIP with the following command: /usr/bin/csrutil status | /usr/bin/grep -c 'System Integrity Protection status: enabled.' If the result is not "1", this is a finding.
Fix
To configure the macOS system to enable SIP, boot into "Recovery" mode, launch "Terminal" from the "Utilities" menu, and run the following command: /usr/bin/csrutil enable
-
The macOS system must enforce FileVault.
Check
Verify the macOS system is configured to enforce FileVault with the following command: dontAllowDisable=$(/usr/bin/osascript -l JavaScript << EOS $.NSUserDefaults.alloc.initWithSuiteName('com.apple.MCX')\ .objectForKey('dontAllowFDEDisable').js EOS ) fileVault=$(/usr/bin/fdesetup status | /usr/bin/grep -c "FileVault is On.") if [[ "$dontAllowDisable" == "true" ]] && [[ "$fileVault" == 1 ]]; then echo "1" else echo "0" fi If the result is not "1", this is a finding.
Fix
Refer to the FileVault supplemental to implement this rule. Configure the macOS system to enforce FileVault by installing the "com.apple.MCX" configuration profile.
-
The macOS system must be a version supported by the vendor.
Maps to SA-22 via CCI-003376Check
Verify the operating system version. Click the Apple icon on the menu at the top left corner of the screen. Select the "About This Mac" option. If the operating system version is no longer supported by the vendor, this is a finding.
Fix
Upgrade to a supported version of the operating system.
-
The macOS system must install security-relevant software updates within 30 days unless the time period is directed by an authoritative source (e.g., IAVM, CTOs, DTMs, STIGs).
Maps to SI-2 via CCI-002605Check
Verify security-relevant software updates are installed on the operating system within 30 days with the following command: softwareupdate_date_epoch=$(/bin/date -j -f "%Y-%m-%d" "$(/usr/bin/defaults read /Library/Preferences/com.apple.SoftwareUpdate.plist LastFullSuccessfulDate | /usr/bin/awk '{print $1}')" "+%s") thirty_days_epoch=$(/bin/date -v -30d "+%s") if [[ $softwareupdate_date_epoch -lt $thirty_days_epoch ]]; then /bin/echo "0" else /bin/echo "1" fi If the result is not "1", this is a finding.
Fix
Install the latest updates within 30 days unless the time period is directed by an authoritative source (e.g., IAVM, CTOs, DTMs, STIGs). https://support.apple.com/en-us/108382 If enrolled in an MDM, consult the MDM's documentation for automated methods.