diff --git a/default/serverspec/os_spec.rb b/default/serverspec/os_spec.rb index b5753b1..6f41d8b 100644 --- a/default/serverspec/os_spec.rb +++ b/default/serverspec/os_spec.rb @@ -62,57 +62,38 @@ describe file('/etc/login.defs') do end # GIS: Req 3.21-12 -describe 'SUID/ SGID whitelist check' do - it 'found only whitelist suid/sgid' do - whitelist = [ - # whitelist as provided by NSA - '/bin/mount', '/bin/ping', '/bin/su', '/bin/umount', '/sbin/pam_timestamp_check', - '/sbin/unix_chkpwd', '/usr/bin/at', '/usr/bin/gpasswd', '/usr/bin/locate', - '/usr/bin/newgrp', '/usr/bin/passwd', '/usr/bin/ssh-agent', '/usr/libexec/utempter/utempter', '/usr/sbin/lockdev', - '/usr/sbin/sendmail.sendmail', '/usr/bin/expiry', - # whitelist ipv6 - '/bin/ping6', '/usr/bin/traceroute6.iputils', - # whitelist nfs - '/sbin/mount.nfs', '/sbin/umount.nfs', - # whitelist nfs4 - '/sbin/mount.nfs4', '/sbin/umount.nfs4', - # whitelist cron - '/usr/bin/crontab', - # whitelist consolemssaging - '/usr/bin/wall', '/usr/bin/write', - # whitelist: only SGID with utmp group for multi-session access - # impact is limited; installation/usage has some remaining risk - '/usr/bin/screen', - # whitelist locate - '/usr/bin/mlocate', - # whitelist usermanagement - '/usr/bin/chage', '/usr/bin/chfn', '/usr/bin/chsh', - # whitelist fuse - '/bin/fusermount', - # whitelist pkexec - '/usr/bin/pkexec', - # whitelist sudo - '/usr/bin/sudo', '/usr/bin/sudoedit', - # whitelist postfix - '/usr/sbin/postdrop', '/usr/sbin/postqueue', - # whitelist apache - '/usr/sbin/suexec', - # whitelist squid - '/usr/lib/squid/ncsa_auth', '/usr/lib/squid/pam_auth', - # whitelist kerberos - '/usr/kerberos/bin/ksu', - # whitelist pam_caching - '/usr/sbin/ccreds_validate', - # whitelist Xorg - '/usr/bin/Xorg', # xorg - '/usr/bin/X', # xorg - '/usr/lib/dbus-1.0/dbus-daemon-launch-helper', # freedesktop ipc - '/usr/lib/vte/gnome-pty-helper', # gnome - '/usr/lib/libvte9/gnome-pty-helper', # gnome - '/usr/lib/libvte-2.90-9/gnome-pty-helper' # gnome +describe 'SUID/ SGID blacklist check' do + it 'found no blacklisted suid/sgid' do + blacklist = [ + # blacklist as provided by NSA + '/usr/bin/rcp', '/usr/bin/rlogin', '/usr/bin/rsh', + # sshd must not use host-based authentication (see ssh cookbook) + '/usr/libexec/openssh/ssh-keysign', + '/usr/lib/openssh/ssh-keysign', + # misc others + '/sbin/netreport', # not normally required for user + '/usr/sbin/usernetctl', # modify interfaces via functional accounts + # connecting to ... + '/usr/sbin/userisdnctl', # no isdn... + '/usr/sbin/pppd', # no ppp / dsl ... + # lockfile + '/usr/bin/lockfile', + '/usr/bin/mail-lock', + '/usr/bin/mail-unlock', + '/usr/bin/mail-touchlock', + '/usr/bin/dotlockfile', + # need more investigation, blacklist for now + '/usr/bin/arping', + '/usr/sbin/uuidd', + '/usr/bin/mtr', # investigate current state... + '/usr/lib/evolution/camel-lock-helper-1.2', # investigate current state... + '/usr/lib/pt_chown', # pseudo-tty, needed? + '/usr/lib/eject/dmcrypt-get-device', + '/usr/lib/mc/cons.saver' # midnight commander screensaver ] + actual = command('find / -perm -4000 -o -perm -2000 -type f ! -path \'/proc/*\' -print 2>/dev/null | grep -v \'^find:\'').stdout.split(/\r?\n/) - (actual - whitelist).count.should be 0 + (actual & blacklist).count.should be 0 end end diff --git a/modules_disabled/serverspec/modules_spec.rb b/lockdown/serverspec/modules_spec.rb similarity index 100% rename from modules_disabled/serverspec/modules_spec.rb rename to lockdown/serverspec/modules_spec.rb diff --git a/lockdown/serverspec/os_spec.rb b/lockdown/serverspec/os_spec.rb new file mode 100644 index 0000000..b5753b1 --- /dev/null +++ b/lockdown/serverspec/os_spec.rb @@ -0,0 +1,129 @@ +# encoding: utf-8 +# +# Copyright 2014, Deutsche Telekom AG +# +# 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. +# + +require 'spec_helper' + +RSpec.configure do |c| + c.filter_run_excluding skipOn: backend(Serverspec::Commands::Base).check_os[:family] +end + +# GIS: Req 3.21-4 +describe command('find / -name \'.rhosts\' | wc -l ') do + its(:stdout) { should match(/^0/) } +end + +# GIS: Req 3.21-4 +describe command('find / -name \'hosts.equiv\' | wc -l ') do + its(:stdout) { should match(/^0/) } +end + +# GIS: Req 3.21-7 +describe file('/etc/shadow') do + it { should be_owned_by 'root' } +end + +# GIS: Req 3.21-7 +describe file('/etc/shadow') do + it { should be_mode 600 } +end + +# GIS: Req 3.21-8 +describe command('echo $PATH | grep -ci \'\.\'') do + its(:stdout) { should match(/^0/) } +end + +# GIS: Req 3.21-8 +describe file('/etc/login.defs') do + its(:content) { should match(%r{^ENV_SUPATH\s+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin}) } +end + +# GIS: Req 3.21-8 +describe file('/etc/login.defs') do + its(:content) { should match(%r{^ENV_PATH\s+PATH=/usr/local/bin:/usr/bin:/bin}) } +end + +# GIS: Req 3.21-10 +describe file('/etc/login.defs') do + its(:content) { should match(/^UMASK +027/) } +end + +# GIS: Req 3.21-12 +describe 'SUID/ SGID whitelist check' do + it 'found only whitelist suid/sgid' do + whitelist = [ + # whitelist as provided by NSA + '/bin/mount', '/bin/ping', '/bin/su', '/bin/umount', '/sbin/pam_timestamp_check', + '/sbin/unix_chkpwd', '/usr/bin/at', '/usr/bin/gpasswd', '/usr/bin/locate', + '/usr/bin/newgrp', '/usr/bin/passwd', '/usr/bin/ssh-agent', '/usr/libexec/utempter/utempter', '/usr/sbin/lockdev', + '/usr/sbin/sendmail.sendmail', '/usr/bin/expiry', + # whitelist ipv6 + '/bin/ping6', '/usr/bin/traceroute6.iputils', + # whitelist nfs + '/sbin/mount.nfs', '/sbin/umount.nfs', + # whitelist nfs4 + '/sbin/mount.nfs4', '/sbin/umount.nfs4', + # whitelist cron + '/usr/bin/crontab', + # whitelist consolemssaging + '/usr/bin/wall', '/usr/bin/write', + # whitelist: only SGID with utmp group for multi-session access + # impact is limited; installation/usage has some remaining risk + '/usr/bin/screen', + # whitelist locate + '/usr/bin/mlocate', + # whitelist usermanagement + '/usr/bin/chage', '/usr/bin/chfn', '/usr/bin/chsh', + # whitelist fuse + '/bin/fusermount', + # whitelist pkexec + '/usr/bin/pkexec', + # whitelist sudo + '/usr/bin/sudo', '/usr/bin/sudoedit', + # whitelist postfix + '/usr/sbin/postdrop', '/usr/sbin/postqueue', + # whitelist apache + '/usr/sbin/suexec', + # whitelist squid + '/usr/lib/squid/ncsa_auth', '/usr/lib/squid/pam_auth', + # whitelist kerberos + '/usr/kerberos/bin/ksu', + # whitelist pam_caching + '/usr/sbin/ccreds_validate', + # whitelist Xorg + '/usr/bin/Xorg', # xorg + '/usr/bin/X', # xorg + '/usr/lib/dbus-1.0/dbus-daemon-launch-helper', # freedesktop ipc + '/usr/lib/vte/gnome-pty-helper', # gnome + '/usr/lib/libvte9/gnome-pty-helper', # gnome + '/usr/lib/libvte-2.90-9/gnome-pty-helper' # gnome + ] + actual = command('find / -perm -4000 -o -perm -2000 -type f ! -path \'/proc/*\' -print 2>/dev/null | grep -v \'^find:\'').stdout.split(/\r?\n/) + (actual - whitelist).count.should be 0 + end +end + +# GIS: Req 3.21-16 +describe 'Unique uid' do + it 'check for unique uids' do + actual = command('cat /etc/passwd | cut -d \':\' -f 3').stdout.split(/\r?\n/) + hm = actual.each_with_object(Hash.new(0)) { |d, counts| counts[d] += 1 } + hm.each do |k, v| + str = "User: UID #{k} instances: " + ("#{str}#{v}").should eq("#{str}1") + end + end +end diff --git a/lockdown/serverspec/spec_helper.rb b/lockdown/serverspec/spec_helper.rb new file mode 100644 index 0000000..f844cc5 --- /dev/null +++ b/lockdown/serverspec/spec_helper.rb @@ -0,0 +1,73 @@ +# encoding: utf-8 +# +# Copyright 2014, Deutsche Telekom AG +# +# 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. +# + +if ENV['STANDALONE_SPEC'] + + require 'serverspec' + require 'pathname' + require 'net/ssh' + require 'highline/import' + + include Serverspec::Helper::Ssh + include Serverspec::Helper::DetectOS + + RSpec.configure do |c| + + if ENV['ASK_SUDO_PASSWORD'] + c.sudo_password = ask('Enter sudo password: ') { |q| q.echo = false } + else + c.sudo_password = ENV['SUDO_PASSWORD'] + end + + options = {} + + if ENV['ASK_LOGIN_PASSWORD'] + options[:password] = ask("\nEnter login password: ") { |q| q.echo = false } + else + options[:password] = ENV['LOGIN_PASSWORD'] + end + + if ENV['ASK_LOGIN_USERNAME'] + user = ask("\nEnter login username: ") { |q| q.echo = false } + else + user = ENV['LOGIN_USERNAME'] || ENV['user'] || Etc.getlogin + end + + if user.nil? + puts 'specify login user env LOGIN_USERNAME= or user=' + exit 1 + end + + c.host = ENV['TARGET_HOST'] + options.merge(Net::SSH::Config.for(c.host)) + c.ssh = Net::SSH.start(c.host, user, options) + c.os = backend.check_os + + end + +else + require 'serverspec' + + include Serverspec::Helper::Exec + include Serverspec::Helper::DetectOS + + RSpec.configure do |c| + c.before :all do + c.path = '/sbin:/usr/sbin' + end + end +end diff --git a/lockdown/serverspec/sysctl_spec.rb b/lockdown/serverspec/sysctl_spec.rb new file mode 100644 index 0000000..cb1cd30 --- /dev/null +++ b/lockdown/serverspec/sysctl_spec.rb @@ -0,0 +1,224 @@ +# encoding: utf-8 +# +# Copyright 2014, Deutsche Telekom AG +# +# 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. +# + +require 'spec_helper' + +RSpec.configure do |c| + c.filter_run_excluding skipOn: backend(Serverspec::Commands::Base).check_os[:family] +end + +describe 'IP V4 networking' do + + # GIS: Req 3.21-1 + context linux_kernel_parameter('net.ipv4.ip_forward') do + its(:value) { should eq 0 } + end + + # GIS: Req 3.21-1 + context linux_kernel_parameter('net.ipv4.conf.all.forwarding') do + its(:value) { should eq 0 } + end + + # GIS: Req 3.21-3 + context linux_kernel_parameter('net.ipv4.conf.all.rp_filter') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.21-3 ; GIS: Req 3.37-10 + context linux_kernel_parameter('net.ipv4.conf.default.rp_filter') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.21-1 + context linux_kernel_parameter('net.ipv4.icmp_echo_ignore_broadcasts') do + its(:value) { should eq 1 } + end + + context linux_kernel_parameter('net.ipv4.icmp_ignore_bogus_error_responses') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.01-9 + context linux_kernel_parameter('net.ipv4.icmp_ratelimit') do + its(:value) { should eq 100 } + end + + context linux_kernel_parameter('net.ipv4.icmp_ratemask') do + its(:value) { should eq 88089 } + end + + context linux_kernel_parameter('net.ipv4.tcp_timestamps') do + its(:value) { should eq 0 } + end + + # GIS: Req 3.21-3 + context linux_kernel_parameter('net.ipv4.conf.all.arp_ignore') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.21-3 + context linux_kernel_parameter('net.ipv4.conf.all.arp_announce') do + its(:value) { should eq 2 } + end + + context linux_kernel_parameter('net.ipv4.tcp_rfc1337') do + its(:value) { should eq 1 } + end + + context linux_kernel_parameter('net.ipv4.tcp_syncookies') do + its(:value) { should eq 1 } + end + + context linux_kernel_parameter('net.ipv4.conf.all.shared_media') do + its(:value) { should eq 1 } + end + + context linux_kernel_parameter('net.ipv4.conf.default.shared_media') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.37-12 + context linux_kernel_parameter('net.ipv4.conf.all.accept_source_route') do + its(:value) { should eq 0 } + end + + # GIS: Req 3.37-12 + context linux_kernel_parameter('net.ipv4.conf.default.accept_source_route') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.default.accept_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.all.accept_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.all.secure_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.default.secure_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.all.send_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv4.conf.all.send_redirects') do + its(:value) { should eq 0 } + end + + # log_martians can cause a denial of service attack to the host + context linux_kernel_parameter('net.ipv4.conf.all.log_martians') do + its(:value) { should eq 0 } + end + +end + +describe 'IP V6 Networking' do + + context linux_kernel_parameter('net.ipv6.conf.all.disable_ipv6') do + its(:value) { should eq 1 } + end + + # GIS: Req 3.21-1 + context linux_kernel_parameter('net.ipv6.conf.all.forwarding') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.accept_redirects') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.all.accept_redirects') do + its(:value) { should eq 0 } + end + +end + +describe 'NSA 2.5.3.2.5 Limit Network-Transmitted Configuration' do + + context linux_kernel_parameter('net.ipv6.conf.default.router_solicitations') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.accept_ra_rtr_pref') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.accept_ra_pinfo') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.accept_ra_defrtr') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.autoconf') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.dad_transmits') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('net.ipv6.conf.default.max_addresses') do + its(:value) { should eq 1 } + end + +end + +describe 'System sysctl' do + + context linux_kernel_parameter('kernel.modules_disabled') do + its(:value) { should eq 1 } + end + + context linux_kernel_parameter('kernel.sysrq') do + its(:value) { should eq 0 } + end + + context linux_kernel_parameter('fs.suid_dumpable') do + its(:value) { should eq 0 } + end +end + +describe 'ExecShield' do + + # GIS: Req 3.21-5 + # check if we find the nx flag + if command('cat /proc/cpuinfo').return_stdout?(/^flags.*?:.*? nx( .*?)?$/) + true + else + # if no nx flag is present, we require exec-shield + context 'No nx flag detected' do + it 'require kernel.exec-shield' do + context linux_kernel_parameter('kernel.exec-shield') do + its(:value) { should eq 1 } + end + end + end + end + + # GIS: Req 3.21-5 + context linux_kernel_parameter('kernel.randomize_va_space') do + its(:value) { should eq 2 } + end +end diff --git a/modules_disabled/serverspec/spec_helper.rb b/modules_disabled/serverspec/spec_helper.rb deleted file mode 100644 index 9323aea..0000000 --- a/modules_disabled/serverspec/spec_helper.rb +++ /dev/null @@ -1,28 +0,0 @@ -# encoding: utf-8 -# -# Copyright 2014, Deutsche Telekom AG -# -# 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. -# - -require 'serverspec' -require 'pathname' - -include Serverspec::Helper::Exec -include Serverspec::Helper::DetectOS - -RSpec.configure do |c| - c.before :all do - c.os = backend(Serverspec::Commands::Base).check_os - end -end diff --git a/modules_disabled/serverspec/sysctl_spec.rb b/modules_disabled/serverspec/sysctl_spec.rb deleted file mode 100644 index 6718f9a..0000000 --- a/modules_disabled/serverspec/sysctl_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# encoding: utf-8 -# -# Copyright 2014, Deutsche Telekom AG -# -# 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. -# - -require 'spec_helper' - -describe 'System sysctl' do - - context linux_kernel_parameter('kernel.modules_disabled') do - its(:value) { should eq 1 } - end - -end