Add CIS checks for 5.4 and 5.5 (#9747)

#9260

- [X] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- ~[ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)~
- ~[ ] Documented any permissions changes~
- ~[ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)~
- ~[ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.~
- [X] Added/updated tests
- [X] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [X] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- ~[ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).~
This commit is contained in:
Lucas Manuel Rodriguez 2023-02-09 12:35:43 -03:00 committed by GitHub
parent a23ce1b0a2
commit 7fc3613dc5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 373 additions and 5 deletions

View File

@ -220,7 +220,7 @@ spec:
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure Time Is Set Within Appropriate Limits (fleetd required)
name: CIS - Ensure Time Is Set Within Appropriate Limits (Fleetd Required)
platforms: macOS
platform: darwin
description: |
@ -1033,7 +1033,7 @@ spec:
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure Users' Accounts Do Not Have a Password Hint (fleetd required)
name: CIS - Ensure Users' Accounts Do Not Have a Password Hint (Fleetd Required)
platforms: macOS
platform: darwin
description: |
@ -1640,7 +1640,7 @@ spec:
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure Password Age Is Configured (fleetd required)
name: CIS - Ensure Password Age Is Configured (Fleetd Required)
platforms: macOS
platform: darwin
description: |
@ -1665,7 +1665,7 @@ spec:
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure Password History Is Configured (fleetd required)
name: CIS - Ensure Password History Is Configured (Fleetd Required)
platforms: macOS
platform: darwin
description: |
@ -1683,6 +1683,60 @@ spec:
---
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure the Sudo Timeout Period Is Set to Zero (Fleetd Required)
platforms: macOS
platform: darwin
description: |
The sudo command stays logged in as the root user for five minutes before timing out and re-requesting a password.
This five-minute window should be eliminated since it leaves the system extremely vulnerable.
resolution: |
Automated method:
Ask your system administrator to deploy the following script:
echo 'Defaults timestamp_timeout=0' | sudo tee -a /etc/sudoers.d/CIS_54_sudoconfiguration
/usr/bin/sudo /usr/sbin/chown -R root:wheel /etc/sudoers.d/
query: |
SELECT 1 WHERE EXISTS(
SELECT * FROM file WHERE path = '/etc/sudoers.d' AND uid = 0 AND gid = 0
) AND EXISTS(
SELECT
COALESCE(JSON_EXTRACT(
json_result, '$.Authentication timestamp timeout'
), '') AS authentication_timestamp_timeout
FROM sudo_info WHERE authentication_timestamp_timeout = '0.0 minutes'
);
purpose: Informational
tags: compliance, CIS, CIS_Level1, CIS5.4
---
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure a Separate Timestamp Is Enabled for Each User/tty (Fleetd Required)
platforms: macOS
platform: darwin
description: |
Using tty tickets ensures that a user must enter the sudo password in each Terminal session.
With sudo versions 1.8 and higher, introduced in 10.12, the default value is to have tty tickets
for each interface so that root access is limited to a specific terminal.
The default configuration can be overwritten or not configured correctly on earlier versions of macOS.
resolution: |
Automated method:
Ask your system administrator to deploy the following script:
echo 'Defaults timestamp_type=tty' | sudo tee /etc/sudoers.d/CIS_55_sudoconfiguration
query: |
SELECT 1 WHERE EXISTS(
SELECT
COALESCE(JSON_EXTRACT(
json_result, '$.Type of authentication timestamp record'
), '') AS type_of_auth_timestamp_record
FROM sudo_info WHERE type_of_auth_timestamp_record = 'tty'
);
purpose: Informational
tags: compliance, CIS, CIS_Level1, CIS5.5
contributors: lucasmrod
---
apiVersion: v1
kind: policy
spec:
name: CIS - Ensure an Administrator Account Cannot Login to Another User's Active and Locked Session (Fleetd Required)
platforms: macOS

View File

@ -0,0 +1,4 @@
#!/bin/bash
echo 'Defaults timestamp_timeout=0' | sudo tee /etc/sudoers.d/CIS_54_sudoconfiguration
/usr/bin/sudo /usr/sbin/chown -R root:wheel /etc/sudoers.d/

View File

@ -0,0 +1,3 @@
#!/bin/bash
echo 'Defaults timestamp_type=tty' | sudo tee /etc/sudoers.d/CIS_55_sudoconfiguration

View File

@ -0,0 +1 @@
* Add `sudo_info` table to Orbit for CIS checks 5.4 and 5.5 on macOS.

View File

@ -9,6 +9,7 @@ import (
"github.com/fleetdm/fleet/v4/orbit/pkg/table/pmset"
"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/sudo_info"
"github.com/fleetdm/fleet/v4/orbit/pkg/table/user_login_settings"
"github.com/macadmins/osquery-extension/tables/filevaultusers"
"github.com/macadmins/osquery-extension/tables/macos_profiles"
@ -29,6 +30,7 @@ func platformTables() []osquery.OsqueryPlugin {
table.NewPlugin("nvram_info", nvram_info.Columns(), nvram_info.Generate),
table.NewPlugin("authdb", authdb.Columns(), authdb.Generate),
table.NewPlugin("pmset", pmset.Columns(), pmset.Generate),
table.NewPlugin("sudo_info", sudo_info.Columns(), sudo_info.Generate),
// Macadmins extension tables
table.NewPlugin("filevault_users", filevaultusers.FileVaultUsersColumns(), filevaultusers.FileVaultUsersGenerate),

View File

@ -0,0 +1,76 @@
//go:build darwin
// +build darwin
package sudo_info
import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"os/exec"
"strings"
"github.com/osquery/osquery-go/plugin/table"
)
// Columns is the schema of the table.
func Columns() []table.ColumnDefinition {
return []table.ColumnDefinition{
table.TextColumn("json_result"),
}
}
// 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) {
out, err := exec.Command("/usr/bin/sudo", "-V").Output()
if err != nil {
return nil, fmt.Errorf("command failed: %w", err)
}
result := parseSudoVOutput(out)
jsonResult, err := json.Marshal(result)
if err != nil {
return nil, err
}
return []map[string]string{{
"json_result": string(jsonResult),
}}, nil
}
func parseSudoVOutput(output []byte) map[string]interface{} {
scanner := bufio.NewScanner(bytes.NewReader(output))
result := make(map[string]interface{})
curKey := ""
for scanner.Scan() {
line := scanner.Text()
if strings.TrimSpace(line) == "" {
continue
}
if line[0] == ' ' || line[0] == '\t' {
if result[curKey] == nil {
result[curKey] = []string{}
}
result[curKey] = append(result[curKey].([]string), strings.TrimSpace(line))
continue
}
colonIndex := strings.IndexByte(line, ':')
if colonIndex == -1 {
curKey = line
result[line] = nil
continue
}
if colonIndex == len(line)-1 {
curKey = line[:len(line)-1]
continue
}
result[line[0:colonIndex]] = line[colonIndex+2:] // +2 because of space character after colon
}
return result
}

View File

@ -0,0 +1,216 @@
//go:build darwin
// +build darwin
package sudo_info
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
)
func TestParseSudoVOutput(t *testing.T) {
const sample = `Sudo version 1.9.5p2
Configure options: --with-password-timeout=0 --disable-setreuid --with-env-editor --with-pam --with-libraries=bsm --with-noexec=no --sysconfdir=/private/etc --without-lecture --enable-static-sudoers --with-rundir=/var/db/sudo
Sudoers policy plugin version 1.9.5p2
Sudoers file grammar version 48
Sudoers path: /etc/sudoers
Authentication methods: 'pam'
Syslog facility if syslog is being used for logging: authpriv
Syslog priority to use when user authenticates successfully: notice
Syslog priority to use when user authenticates unsuccessfully: alert
Send mail if the user is not in sudoers
Lecture user the first time they run sudo
File containing the sudo lecture: /etc/sudo_lecture
Require users to authenticate by default
Root may run sudo
Allow some information gathering to give useful error messages
Visudo will honor the EDITOR environment variable
Set the LOGNAME and USER environment variables
Length at which to wrap log file lines (0 for no wrap): 80
Authentication timestamp timeout: 5.0 minutes
Password prompt timeout: 0.0 minutes
Number of tries to enter a password: 3
Umask to use or 0777 to use user's: 022
Path to mail program: /usr/sbin/sendmail
Flags for mail program: -t
Address to send mail to: root
Subject line for mail messages: *** SECURITY information for %h ***
Incorrect password message: Sorry, try again.
Path to lecture status dir: /var/db/sudo/lectured
Path to authentication timestamp dir: /var/db/sudo/ts
Default password prompt: Password:
Default user to run commands as: root
Path to the editor for use by visudo: /usr/bin/vi
When to require a password for 'list' pseudocommand: any
When to require a password for 'verify' pseudocommand: all
File descriptors >= 3 will be closed before executing a command
Reset the environment to a default set of variables
Environment variables to check for safety:
TZ
TERM
LINGUAS
LC_*
LANGUAGE
LANG
COLORTERM
Environment variables to remove:
*=()*
RUBYOPT
RUBYLIB
PYTHONUSERBASE
PYTHONINSPECT
PYTHONPATH
PYTHONHOME
TMPPREFIX
ZDOTDIR
READNULLCMD
NULLCMD
FPATH
PERL5DB
PERL5OPT
PERL5LIB
PERLLIB
PERLIO_DEBUG
JAVA_TOOL_OPTIONS
SHELLOPTS
BASHOPTS
GLOBIGNORE
PS4
BASH_ENV
ENV
TERMCAP
TERMPATH
TERMINFO_DIRS
TERMINFO
DYLD_*
_RLD*
LD_*
PATH_LOCALE
NLSPATH
HOSTALIASES
RES_OPTIONS
LOCALDOMAIN
CDPATH
IFS
Environment variables to preserve:
MAIL
HOME
VISUAL
EDITOR
TZ
SSH_AUTH_SOCK
LSCOLORS
COLUMNS
LINES
LC_TIME
LC_NUMERIC
LC_MONETARY
LC_MESSAGES
LC_CTYPE
LC_COLLATE
LC_ALL
LANGUAGE
LANG
CHARSET
__CF_USER_TEXT_ENCODING
COLORTERM
COLORFGBG
BLOCKSIZE
XAUTHORIZATION
XAUTHORITY
PS2
PS1
PATH
LS_COLORS
KRB5CCNAME
HOSTNAME
DISPLAY
COLORS
Locale to use while parsing sudoers: C
Compress I/O logs using zlib
Directory in which to store input/output logs: /var/log/sudo-io
File in which to store the input/output log: %{seq}
Add an entry to the utmp/utmpx file when allocating a pty
PAM service name to use: sudo
PAM service name to use for login shells: sudo
Attempt to establish PAM credentials for the target user
Create a new PAM session for the command to run in
Perform PAM account validation management
Enable sudoers netgroup support
Check parent directories for writability when editing files with sudoedit
Allow commands to be run even if sudo cannot write to the audit log
Allow commands to be run even if sudo cannot write to the log file
Log entries larger than this value will be split into multiple syslog messages: 960
File mode to use for the I/O log files: 0600
Execute commands by file descriptor instead of by path: digest_only
Type of authentication timestamp record: tty
Ignore case when matching user names
Ignore case when matching group names
Log when a command is allowed by sudoers
Log when a command is denied by sudoers
Sudo log server timeout in seconds: 30
Enable SO_KEEPALIVE socket option on the socket connected to the logserver
Verify that the log server's certificate is valid
Set the pam remote user to the user running sudo
The format of logs to produce: sudo
Local IP address and netmask pairs:
fe80::aede:48ff:fe00:1122/ffff:ffff:ffff:ffff::
fe80::142f:6d87:1e52:591d/ffff:ffff:ffff:ffff::
192.168.0.230/255.255.255.0
fe80::70f9:67ff:fe50:983f/ffff:ffff:ffff:ffff::
fe80::70f9:67ff:fe50:983f/ffff:ffff:ffff:ffff::
fe80::8372:c8a:ecf8:40b5/ffff:ffff:ffff:ffff::
fe80::612f:3c9d:f33a:9e7d/ffff:ffff:ffff:ffff::
fe80::ce81:b1c:bd2c:69e/ffff:ffff:ffff:ffff::
192.168.103.1/255.255.255.0
fe80::682f:67ff:fee8:7464/ffff:ffff:ffff:ffff::
172.16.132.1/255.255.255.0
fe80::682f:67ff:fee8:7465/ffff:ffff:ffff:ffff::
Sudoers I/O plugin version 1.9.5p2
Sudoers audit plugin version 1.9.5p2`
result := parseSudoVOutput([]byte(sample))
_, err := json.Marshal(result)
require.NoError(t, err)
// First line.
require.Contains(t, result, "Sudo version 1.9.5p2")
require.Nil(t, result["Sudo version 1.9.5p2"])
// Key without value.
require.Contains(t, result, "Compress I/O logs using zlib")
require.Nil(t, result["Compress I/O logs using zlib"])
// Key and value pairs defined in one line.
require.Equal(t, "C", result["Locale to use while parsing sudoers"])
require.Equal(t, "tty", result["Type of authentication timestamp record"])
require.Equal(t, "5.0 minutes", result["Authentication timestamp timeout"])
// Last line.
require.Contains(t, result, "Sudoers audit plugin version 1.9.5p2")
require.Nil(t, result["Sudoers audit plugin version 1.9.5p2"])
// Key and value paris defined in multiple lines
v := result["Local IP address and netmask pairs"]
require.NotNil(t, v)
localIPAddrAndNetmaskPairs, ok := v.([]string)
require.True(t, ok)
require.Len(t, localIPAddrAndNetmaskPairs, 12)
require.Contains(t, localIPAddrAndNetmaskPairs, "fe80::aede:48ff:fe00:1122/ffff:ffff:ffff:ffff::")
require.Contains(t, localIPAddrAndNetmaskPairs, "192.168.103.1/255.255.255.0")
require.Contains(t, localIPAddrAndNetmaskPairs, "fe80::682f:67ff:fee8:7465/ffff:ffff:ffff:ffff::")
v = result["Environment variables to preserve"]
require.NotNil(t, v)
envVariablesToPreserve, ok := v.([]string)
require.True(t, ok)
require.Len(t, envVariablesToPreserve, 33)
require.Contains(t, envVariablesToPreserve, "MAIL")
require.Contains(t, envVariablesToPreserve, "COLORS")
// Line with multiple colons:
require.Equal(t, "Password: ", result["Default password prompt"])
}

View File

@ -0,0 +1,12 @@
name: sudo_info
platforms:
- darwin
description: Returns the output of `sudo -V` in JSON format.
columns:
- name: json_result
type: text
required: false
description: A JSON document with the key value pairs parsed from `sudo -V` output.
notes: >-
- This table is not a core osquery table. It is included as part of Fleetd, the osquery manager from Fleet.
evented: false

View File

@ -24,7 +24,7 @@ if [[ -d "$TUF_PATH" ]]; then
exit 0
fi
OSQUERY_MACOS_APP_BUNDLE_VERSION=5.6.0
OSQUERY_MACOS_APP_BUNDLE_VERSION=5.7.0
SYSTEMS=${SYSTEMS:-macos linux windows}
mkdir -p $TUF_PATH/tmp