-
Notifications
You must be signed in to change notification settings - Fork 190
/
Copy pathos_spec.rb
324 lines (295 loc) · 11.1 KB
/
os_spec.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# frozen_string_literal: true
#
# Copyright 2015, Patrick Muench
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# author: Christoph Hartmann
# author: Dominik Richter
# author: Patrick Muench
login_defs_umask = attribute('login_defs_umask', value: os.redhat? ? '077' : '027', description: 'Default umask to set in login.defs')
login_defs_passmaxdays = attribute('login_defs_passmaxdays', value: '60', description: 'Default password maxdays to set in login.defs')
login_defs_passmindays = attribute('login_defs_passmindays', value: '7', description: 'Default password mindays to set in login.defs')
login_defs_passwarnage = attribute('login_defs_passwarnage', value: '7', description: 'Default password warnage (days) to set in login.defs')
shadow_group = 'root'
shadow_group = 'shadow' if os.debian? || os.suse? || os.name == 'alpine'
container_execution = begin
virtualization.role == 'guest' && virtualization.system =~ /^(lxc|docker)$/
rescue NoMethodError
false
end
blacklist = attribute(
'blacklist',
value: suid_blacklist.default,
description: 'blacklist of suid/sgid program on system'
)
cpuvulndir = '/sys/devices/system/cpu/vulnerabilities/'
control 'os-01' do
impact 1.0
title 'Trusted hosts login'
desc "hosts.equiv file is a weak implemenation of authentication. Disabling the hosts.equiv support helps to prevent users from subverting the system's normal access control mechanisms of the system."
describe file('/etc/hosts.equiv') do
it { should_not exist }
end
end
control 'os-02' do
impact 1.0
title 'Check owner and permissions for /etc/shadow'
desc 'Check periodically the owner and permissions for /etc/shadow'
describe file('/etc/shadow') do
it { should exist }
it { should be_file }
it { should be_owned_by 'root' }
its('group') { should eq shadow_group }
it { should_not be_executable }
it { should_not be_readable.by('other') }
end
if os.redhat? || os.name == 'fedora'
describe file('/etc/shadow') do
it { should_not be_writable.by('owner') }
it { should_not be_readable.by('owner') }
end
else
describe file('/etc/shadow') do
it { should be_writable.by('owner') }
it { should be_readable.by('owner') }
end
end
if os.debian? || os.suse?
describe file('/etc/shadow') do
it { should be_readable.by('group') }
end
else
describe file('/etc/shadow') do
it { should_not be_readable.by('group') }
end
end
end
control 'os-03' do
impact 1.0
title 'Check owner and permissions for /etc/passwd'
desc 'Check periodically the owner and permissions for /etc/passwd'
describe file('/etc/passwd') do
it { should exist }
it { should be_file }
it { should be_owned_by 'root' }
its('group') { should eq 'root' }
it { should_not be_executable }
it { should be_writable.by('owner') }
it { should_not be_writable.by('group') }
it { should_not be_writable.by('other') }
it { should be_readable.by('owner') }
it { should be_readable.by('group') }
it { should be_readable.by('other') }
end
end
control 'os-03b' do
impact 1.0
title 'Check passwords hashes in /etc/passwd'
desc 'Check periodically that /etc/passwd does not contain passwords'
describe passwd do
its('passwords') { should be_in ['x', '*'] }
end
end
control 'os-04' do
impact 1.0
title 'Dot in PATH variable'
desc 'Do not include the current working directory in PATH variable. This makes it easier for an attacker to gain extensive rights by executing a Trojan program'
describe os_env('PATH') do
its('split') { should_not include('') }
its('split') { should_not include('.') }
end
end
control 'os-05' do
impact 1.0
title 'Check login.defs'
desc 'Check owner and permissions for login.defs. Also check the configured PATH variable and umask in login.defs'
describe file('/etc/login.defs') do
it { should exist }
it { should be_file }
it { should be_owned_by 'root' }
its('group') { should eq 'root' }
it { should_not be_executable }
it { should be_readable.by('owner') }
it { should be_readable.by('group') }
it { should be_readable.by('other') }
end
describe login_defs do
its('ENV_SUPATH') { should include('/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin') }
its('ENV_PATH') { should include('/usr/local/bin:/usr/bin:/bin') }
its('UMASK') { should include(login_defs_umask) }
its('PASS_MAX_DAYS') { should eq login_defs_passmaxdays }
its('PASS_MIN_DAYS') { should eq login_defs_passmindays }
its('PASS_WARN_AGE') { should eq login_defs_passwarnage }
its('LOGIN_RETRIES') { should eq '5' }
its('LOGIN_TIMEOUT') { should eq '60' }
its('UID_MIN') { should eq '1000' }
its('GID_MIN') { should eq '1000' }
end
end
control 'os-05b' do
impact 1.0
title 'Check login.defs - RedHat specific'
desc 'Check owner and permissions for login.defs. Also check the configured PATH variable and umask in login.defs'
describe file('/etc/login.defs') do
it { should_not be_writable }
end
describe login_defs do
its('SYS_UID_MIN') { should eq '201' }
its('SYS_UID_MAX') { should eq '999' }
its('SYS_GID_MIN') { should eq '201' }
its('SYS_GID_MAX') { should eq '999' }
end
only_if { os.redhat? }
end
control 'os-06' do
impact 1.0
title 'Check for SUID/ SGID blacklist'
desc 'Find blacklisted SUID and SGID files to ensure that no rogue SUID and SGID files have been introduced into the system'
describe suid_check(blacklist) do
its('diff') { should be_empty }
end
end
control 'os-07' do
impact 1.0
title 'Unique uid and gid'
desc 'Check for unique uids gids'
describe passwd do
its('uids') { should_not contain_duplicates }
end
describe etc_group do
its('gids') { should_not contain_duplicates }
end
end
control 'os-08' do
impact 1.0
title 'Entropy'
desc 'Check system has enough entropy - greater than 1000'
describe file('/proc/sys/kernel/random/entropy_avail').content.to_i do
it { should >= 1000 }
end
end
control 'os-09' do
impact 1.0
title 'Check for .rhosts and .netrc file'
desc 'Find .rhosts and .netrc files - CIS Benchmark 9.2.9-10'
output = command('find / -maxdepth 3 \( -iname .rhosts -o -iname .netrc \) -print 2>/dev/null | grep -v \'^find:\'')
out = output.stdout.split(/\r?\n/)
describe out do
it { should be_empty }
end
end
control 'os-10' do
impact 1.0
title 'CIS: Disable unused filesystems'
desc '1.1.1 Ensure mounting of cramfs, freevxfs, jffs2, hfs, hfsplus, squashfs, udf, FAT'
only_if { !container_execution }
efi_dir = inspec.file('/sys/firmware/efi')
describe file('/etc/modprobe.d/dev-sec.conf') do
its(:content) { should match 'install cramfs /bin/true' }
its(:content) { should match 'install freevxfs /bin/true' }
its(:content) { should match 'install jffs2 /bin/true' }
its(:content) { should match 'install hfs /bin/true' }
its(:content) { should match 'install hfsplus /bin/true' }
its(:content) { should match 'install squashfs /bin/true' }
its(:content) { should match 'install udf /bin/true' }
# if efi is active, do not disable vfat. otherwise the system
# won't boot anymore
unless efi_dir.exist?
its(:content) { should match 'install vfat /bin/true' }
end
end
end
control 'os-11' do
impact 1.0
title 'Protect log-directory'
desc 'The log-directory /var/log should belong to root'
describe file('/var/log') do
it { should be_directory }
it { should be_owned_by 'root' }
its(:group) { should match(/^root|syslog$/) }
end
end
control 'os-12' do
impact 1.0
title 'Detect vulnerabilities in the cpu-vulnerability-directory'
desc 'Check for known cpu vulnerabilities described here: https://www.kernel.org/doc/html/v5.6/admin-guide/hw-vuln/index.html'
only_if { !container_execution }
if file(cpuvulndir).exist?
describe file(cpuvulndir) do
it { should be_directory }
end
loaded_files = command("find #{cpuvulndir} -type f -maxdepth 1").stdout.split(/\n/).map(&:strip).find_all { |vulnfiles| !vulnfiles.empty? }
loaded_files.each do |vulnfile|
describe file(vulnfile) do
its(:content) { should_not match 'vulnerable' }
its(:content) { should_not match 'Vulnerable' }
end
end
end
end
control 'os-13' do
impact 1.0
title 'Protect cron directories and files'
desc 'The cron directories and files should belong to root.'
cron_files = ['/etc/crontab', '/etc/cron.hourly', '/etc/cron.daily', '/etc/cron.weekly', '/etc/cron.monthly', '/etc/cron.d']
cron_files.each do |cron_file|
next unless file(cron_file).exist?
describe file(cron_file) do
it { should be_owned_by 'root' }
it { should_not be_writable.by('group') }
it { should_not be_writable.by('other') }
it { should_not be_readable.by('group') }
it { should_not be_readable.by('other') }
end
end
end
control 'os-15' do
impact 1.0
title 'Check auditd rules'
desc 'Check that the auditd rules are created and active'
output = command('auditctl -l')
describe output do
its(:stdout) { should match '-a always,exit -F arch=b64 -S execve' }
its(:stdout) { should match '-w /etc/localtime -p wa -k time-change' }
its(:stdout) { should match '-w /sbin/insmod -p x -k modules' }
its(:stdout) { should match '-w /etc/crontab' }
its(:stdout) { should match '-w /etc/sudoers -p wa -k scope' }
its(:stdout) { should match '-w /etc/passwd -p wa -k identity' }
its(:stdout) { should match '-w /var/log/audit/audit.log' }
its(:stdout) { should match '-w /etc/hosts -p wa -k system-locale' }
its(:stdout) { should match '-w /etc/ssh/sshd_config' }
if os.redhat? || os.name == 'amazon' || os.name == 'fedora'
its(:stdout) { should match '-w /usr/bin/yum -p x -k software_mgmt' }
its(:stdout) { should match '-w /etc/selinux -p wa -k MAC-policy' }
end
if os.suse?
its(:stdout) { should match '-w /usr/bin/zypper -p x -k software_mgmt' }
end
if os.debian?
its(:stdout) { should match '-w /usr/bin/apt-get -p x -k software_mgmt' }
its(:stdout) { should match '-w /var/log/system.log' }
its(:stdout) { should match '-w /etc/network/interfaces -p wa -k system-locale' }
end
if os.name == 'arch'
its(:stdout) { should match '-w /usr/bin/pacman -p x -k software_mgmt' }
end
if os.redhat? || os.name == 'amazon' || os.name == 'fedora' || os.suse?
its(:stdout) { should match '-w /var/log/messages' }
its(:stdout) { should match '-w /etc/sysconfig/network-scripts -p wa -k system-locale' }
end
if os.suse? || os.debian?
its(:stdout) { should match '-w /etc/apparmor -p wa -k MAC-policy' }
end
end
end