CIS 5.1.3+5.1.4 (#9642)
This commit is contained in:
@@ -1270,6 +1270,42 @@ spec:
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: policy
|
||||
spec:
|
||||
name: CIS - Ensure Apple Mobile File Integrity (AMFI) Is Enabled (fleetd required)
|
||||
platforms: macOS
|
||||
platform: darwin
|
||||
description: |
|
||||
Apple Mobile File Integrity (AMFI) was first released in macOS 10.12. The daemon and service block attempts to run unsigned code. AMFI uses launchd, code signatures, certificates, entitlements, and provisioning profiles to create a filtered entitlement dictionary for an app. AMFI is the macOS kernel module that enforces code-signing and library validation.
|
||||
Note: AMFI cannot be disabled with SIP enabled, but a change attempt can be made that will appear successful, and report incorrectly as successful. If the AMFI audit fails, and the SIP audit passes, this is still an issue the admin should research.
|
||||
resolution: |
|
||||
Automated method:
|
||||
Ask your system administrator to deploy the following script which will Ensure Apple Mobile File Integrity (AMFI) Is Enabled:
|
||||
/usr/bin/sudo /usr/sbin/nvram boot-args=""
|
||||
query: SELECT 1 FROM nvram_info WHERE amfi_enabled="1";
|
||||
purpose: Informational
|
||||
tags: compliance, CIS, CIS_Level1, CIS5.1.3
|
||||
contributors: sharon-fdm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: policy
|
||||
spec:
|
||||
name: CIS - Ensure Sealed System Volume (SSV) Is Enabled (fleetd required)
|
||||
platforms: macOS
|
||||
platform: darwin
|
||||
description: |
|
||||
Sealed System Volume is a security feature introduced in macOS 11.0 Big Sur.
|
||||
During system installation, a SHA-256 cryptographic hash is calculated for all immutable system files and stored in a Merkle tree which itself is hashed as the Seal. Both are stored in the metadata of the snapshot created of the System volume.
|
||||
The seal is verified by the boot loader at startup. macOS will not boot if system files have been tampered with. If validation fails, the user will be instructed to reinstall the operating system.
|
||||
During read operations for files located in the Sealed System Volume, a hash is calculated and compared to the value stored in the Merkle tree.
|
||||
resolution: |
|
||||
If SSV has been disabled, assume that the operating system has been compromised. Back up any files, and do a clean install to a known good Operating System.
|
||||
query: SELECT 1 FROM csrutil_info WHERE ssv_enabled="1";
|
||||
purpose: Informational
|
||||
tags: compliance, CIS, CIS_Level1, CIS5.1.4
|
||||
contributors: sharon-fdm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: policy
|
||||
spec:
|
||||
name: CIS - Ensure Password Account Lockout Threshold Is Configured (Fleetd required)
|
||||
platforms: macOS
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
- Implement table to hold csrutil_info extension via Orbit
|
||||
@@ -0,0 +1 @@
|
||||
- Implement table to hold nvram_info extension via Orbit
|
||||
@@ -0,0 +1,54 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package csrutil_info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/osquery/osquery-go/plugin/table"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Columns is the schema of the table.
|
||||
func Columns() []table.ColumnDefinition {
|
||||
return []table.ColumnDefinition{
|
||||
table.IntegerColumn("ssv_enabled"),
|
||||
}
|
||||
}
|
||||
|
||||
// Generate is called to return the results for the table at query time.
|
||||
// Constraints for generating can be retrieved from the queryContext.
|
||||
func Generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
|
||||
SSVEnabled, err := getSSVEnabled(ctx)
|
||||
return []map[string]string{
|
||||
{"ssv_enabled": SSVEnabled},
|
||||
}, err
|
||||
}
|
||||
|
||||
func getSSVEnabled(ctx context.Context) (SSVEnabled string, err error) {
|
||||
res, err := runCommand(ctx, "/usr/bin/csrutil", "authenticated-root", "status")
|
||||
SSVEnabled = ""
|
||||
if err == nil {
|
||||
SSVEnabled = "0"
|
||||
if strings.Contains(res, "Authenticated Root status: enabled") {
|
||||
SSVEnabled = "1"
|
||||
}
|
||||
}
|
||||
return SSVEnabled, err
|
||||
}
|
||||
|
||||
func runCommand(ctx context.Context, name string, arg ...string) (res string, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, name, arg...)
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("failed while generating csrutil_info table")
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package csrutil_info
|
||||
|
||||
import (
|
||||
"github.com/osquery/osquery-go/plugin/table"
|
||||
"golang.org/x/net/context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
var tbl table.QueryContext
|
||||
|
||||
table, err := Generate(ctx, tbl)
|
||||
if err != nil {
|
||||
t.Fatalf(`Expected no error. got %s`, err)
|
||||
}
|
||||
if table[0]["ssv_enabled"] != "0" && table[0]["ssv_enabled"] != "1" {
|
||||
t.Fatalf(`ssvEnabled expected 0 or 1. got %s`, table[0]["ssvEnabled"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSSVEnabled(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
ssvEnabled, err := getSSVEnabled(ctx)
|
||||
if ssvEnabled != "0" && ssvEnabled != "1" {
|
||||
t.Fatalf(`ssvEnabled expected 0 or 1. got %s`, ssvEnabled)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf(`Expected no error. got %s`, err)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/fleetdm/fleet/v4/orbit/pkg/table/csrutil_info"
|
||||
"github.com/fleetdm/fleet/v4/orbit/pkg/table/nvram_info"
|
||||
"github.com/fleetdm/fleet/v4/orbit/pkg/table/privaterelay"
|
||||
"github.com/fleetdm/fleet/v4/orbit/pkg/table/pwd_policy"
|
||||
"github.com/fleetdm/fleet/v4/orbit/pkg/table/user_login_settings"
|
||||
@@ -22,6 +24,8 @@ func platformTables() []osquery.OsqueryPlugin {
|
||||
table.NewPlugin("icloud_private_relay", privaterelay.Columns(), privaterelay.Generate),
|
||||
table.NewPlugin("user_login_settings", user_login_settings.Columns(), user_login_settings.Generate),
|
||||
table.NewPlugin("pwd_policy", pwd_policy.Columns(), pwd_policy.Generate),
|
||||
table.NewPlugin("csrutil_info", csrutil_info.Columns(), csrutil_info.Generate),
|
||||
table.NewPlugin("nvram_info", nvram_info.Columns(), nvram_info.Generate),
|
||||
|
||||
// Macadmins extension tables
|
||||
table.NewPlugin("filevault_users", filevaultusers.FileVaultUsersColumns(), filevaultusers.FileVaultUsersGenerate),
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package nvram_info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/osquery/osquery-go/plugin/table"
|
||||
"github.com/rs/zerolog/log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Columns is the schema of the table.
|
||||
func Columns() []table.ColumnDefinition {
|
||||
return []table.ColumnDefinition{
|
||||
table.IntegerColumn("amfi_enabled"),
|
||||
}
|
||||
}
|
||||
|
||||
// Generate is called to return the results for the table at query time.
|
||||
// Constraints for generating can be retrieved from the queryContext.
|
||||
func Generate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) {
|
||||
amfiEnabled, err := getAMFIEnabled(ctx)
|
||||
|
||||
return []map[string]string{
|
||||
{"amfi_enabled": amfiEnabled},
|
||||
}, err
|
||||
}
|
||||
|
||||
func getAMFIEnabled(ctx context.Context) (amfiEnabled string, err error) {
|
||||
res, err := runCommand(ctx, "/usr/sbin/nvram", "-p")
|
||||
amfiEnabled = ""
|
||||
if err == nil {
|
||||
amfiEnabled = "0"
|
||||
if !strings.Contains(res, "amfi_get_out_of_my_way=1") {
|
||||
amfiEnabled = "1"
|
||||
}
|
||||
}
|
||||
return amfiEnabled, err
|
||||
}
|
||||
|
||||
func runCommand(ctx context.Context, name string, arg ...string) (res string, err error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
|
||||
defer cancel()
|
||||
cmd := exec.CommandContext(ctx, name, arg...)
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("failed while generating nvram table")
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package nvram_info
|
||||
|
||||
import (
|
||||
"github.com/osquery/osquery-go/plugin/table"
|
||||
"golang.org/x/net/context"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
var tbl table.QueryContext
|
||||
|
||||
table, err := Generate(ctx, tbl)
|
||||
if err != nil {
|
||||
t.Fatalf(`Expected no error. got %s`, err)
|
||||
}
|
||||
if table[0]["amfi_enabled"] != "0" && table[0]["amfi_enabled"] != "1" {
|
||||
t.Fatalf(`amfiEnabled expected 0 or 1. got %s`, table[0]["amfi_enabled"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAMFIEnabled(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
amfiEnabled, err := getAMFIEnabled(ctx)
|
||||
if amfiEnabled != "0" && amfiEnabled != "1" {
|
||||
t.Fatalf(`amfiEnabled expected 0 or 1. got %s`, amfiEnabled)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf(`Expected no error. got %s`, err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: csrutil_info
|
||||
platforms:
|
||||
- darwin
|
||||
description: Information from csrutil system call.
|
||||
columns:
|
||||
- name: ssv_enabled
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
Sealed System Volume is a security feature introduced in macOS 11.0 Big Sur.
|
||||
During system installation, a SHA-256 cryptographic hash is calculated for all immutable system files and stored in a Merkle tree which itself is hashed as the Seal. Both are stored in the metadata of the snapshot created of the System volume.
|
||||
The seal is verified by the boot loader at startup. macOS will not boot if system files have been tampered with. If validation fails, the user will be instructed to reinstall the operating system.
|
||||
During read operations for files located in the Sealed System Volume, a hash is calculated and compared to the value stored in the Merkle tree.
|
||||
notes: >-
|
||||
- This table is not a core osquery table. It is included as part of Fleetd, the osquery manager from Fleet.
|
||||
evented: false
|
||||
@@ -0,0 +1,14 @@
|
||||
name: nvram_info
|
||||
platforms:
|
||||
- darwin
|
||||
description: Information from nvram system call.
|
||||
columns:
|
||||
- name: amfi_enabled
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
Apple Mobile File Integrity (AMFI) was first released in macOS 10.12. The daemon and service block attempts to run unsigned code. AMFI uses lanchd, code signatures, certificates, entitlements, and provisioning profiles to create a filtered entitlement dictionary for an app. AMFI is the macOS kernel module that enforces code-signing and library validation.
|
||||
Note: AMFI cannot be disabled with SIP enabled, but a change attempt can be made that will appear successful, and report incorrectly as successful. If the AMFI audit fails, and the SIP audit passes, this is still an issue the admin should research.
|
||||
notes: >-
|
||||
- This table is not a core osquery table. It is included as part of Fleetd, the osquery manager from Fleet.
|
||||
evented: false
|
||||
@@ -3,22 +3,22 @@ platforms:
|
||||
- darwin
|
||||
description: Password Policiy (e.g max failed password attempts).
|
||||
columns:
|
||||
- name: maxFailedAttempts
|
||||
- name: max_failed_attempts
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
The account lockout threshold specifies the amount of times a user can enter an incorrect password before a lockout will occur. Ensure that a lockout threshold is part of the password policy on the computer.
|
||||
- name: expiresEveryNDays
|
||||
- name: expires_every_n_days
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
How many days for a new password to expire.
|
||||
- name: daysToExpiration
|
||||
- name: days_to_expiration
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
How many days are left for the expiration of the current password.
|
||||
- name: historyDepth
|
||||
- name: history_depth
|
||||
type: integer
|
||||
required: false
|
||||
description: |
|
||||
|
||||
Reference in New Issue
Block a user