├── .github └── workflows │ ├── codespell.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .rubocop.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── controls ├── 1_1_filesystem_configuration.rb ├── 1_2_configure_software_updates.rb ├── 1_3_filesystem_integrity_checking.rb ├── 1_4_secure_boot_settings.rb ├── 1_5_additional_process_hardening.rb ├── 1_6_mandatory_access_control.rb ├── 1_7_warning_banners.rb ├── 1_8_ensure_patches.rb ├── 2_1_inetd_services.rb ├── 2_2_special_purpose_services.rb ├── 2_3_service_clients.rb ├── 3_1_network_parameters_host_only.rb ├── 3_2_network_parameters_host_and_router.rb ├── 3_3_tcp_wrappers.rb ├── 3_4_uncommon_network_protocols.rb ├── 3_5_firewall_configuration.rb ├── 3_6_wireless_interfaces.rb ├── 3_7_disable_ipv6.rb ├── 4_1_configure_system_accounting_auditd.rb ├── 4_2_configure_logging.rb ├── 5_1_configure_cron.rb ├── 5_2_ssh_server_configuration.rb ├── 5_3_configure_pam.rb ├── 5_4_user_accounts_and_environments.rb ├── 6_1_system_file_permissions.rb └── 6_2_user_and_group_settings.rb ├── inspec.yml ├── libraries └── grubconf.rb └── renovate.json /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Codespell - Spellcheck 3 | 4 | on: # yamllint disable-line rule:truthy 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | jobs: 11 | codespell: 12 | uses: "dev-sec/.github/.github/workflows/codespell.yml@main" 13 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: New release 3 | 4 | on: # yamllint disable-line rule:truthy 5 | workflow_dispatch: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | generate_changelog: 12 | uses: dev-sec/.github/.github/workflows/baseline-release.yml@main 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '0 6 * * *' 10 | 11 | jobs: 12 | test: 13 | uses: dev-sec/.github/.github/workflows/baseline-test.yml@main 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | AllCops: 3 | Exclude: 4 | - vendor/**/* 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.4.13](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.13) (2023-12-04) 4 | 5 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.12...0.4.13) 6 | 7 | **Implemented enhancements:** 8 | 9 | - Convert uname variable to global variable [\#159](https://github.com/dev-sec/cis-dil-benchmark/pull/159) ([IvDoorn](https://github.com/IvDoorn)) 10 | - Add alternative package name for iptables [\#156](https://github.com/dev-sec/cis-dil-benchmark/pull/156) ([IvDoorn](https://github.com/IvDoorn)) 11 | - Make all kernel parameter checks related to net.ipv6 conditional [\#155](https://github.com/dev-sec/cis-dil-benchmark/pull/155) ([IvDoorn](https://github.com/IvDoorn)) 12 | - fix: handle chrony configuration sourced via amazon-chrony-config [\#153](https://github.com/dev-sec/cis-dil-benchmark/pull/153) ([nejch](https://github.com/nejch)) 13 | - fix: allow alternative output for sestatus policy [\#152](https://github.com/dev-sec/cis-dil-benchmark/pull/152) ([nejch](https://github.com/nejch)) 14 | - use centralised issue templates and workflows [\#142](https://github.com/dev-sec/cis-dil-benchmark/pull/142) ([schurzi](https://github.com/schurzi)) 15 | 16 | **Fixed bugs:** 17 | 18 | - 3-5 Fix loopback address match [\#161](https://github.com/dev-sec/cis-dil-benchmark/pull/161) ([IvDoorn](https://github.com/IvDoorn)) 19 | - Restrict NX/XD check to the x86 architectures [\#160](https://github.com/dev-sec/cis-dil-benchmark/pull/160) ([IvDoorn](https://github.com/IvDoorn)) 20 | - Local loopback is 127.0.0.0/8, not just 127.0.0.1 [\#147](https://github.com/dev-sec/cis-dil-benchmark/pull/147) ([bendres97](https://github.com/bendres97)) 21 | 22 | **Closed issues:** 23 | 24 | - cis-dil-benchmark-5.6 Ubuntu does not have group 'wheel' [\#138](https://github.com/dev-sec/cis-dil-benchmark/issues/138) 25 | - Add support for arm64 architectures [\#130](https://github.com/dev-sec/cis-dil-benchmark/issues/130) 26 | - cis-dil-benchmark-2.2.1.3 assumes user `chrony` exists [\#129](https://github.com/dev-sec/cis-dil-benchmark/issues/129) 27 | - Missing release for 0.4.12? [\#123](https://github.com/dev-sec/cis-dil-benchmark/issues/123) 28 | 29 | **Merged pull requests:** 30 | 31 | - Extend checks for the filesystem configuration [\#158](https://github.com/dev-sec/cis-dil-benchmark/pull/158) ([IvDoorn](https://github.com/IvDoorn)) 32 | - Ignore unknown syscalls on aarch64 [\#157](https://github.com/dev-sec/cis-dil-benchmark/pull/157) ([IvDoorn](https://github.com/IvDoorn)) 33 | - fix: cis-dil-benchmark-2.2.1.3 read /etc/chrony.d [\#154](https://github.com/dev-sec/cis-dil-benchmark/pull/154) ([IvDoorn](https://github.com/IvDoorn)) 34 | - add spellchecking with codespell [\#151](https://github.com/dev-sec/cis-dil-benchmark/pull/151) ([schurzi](https://github.com/schurzi)) 35 | - Configure Renovate [\#150](https://github.com/dev-sec/cis-dil-benchmark/pull/150) ([renovate[bot]](https://github.com/apps/renovate)) 36 | - Remove control for group 'wheel', since it is not required by benchmark [\#139](https://github.com/dev-sec/cis-dil-benchmark/pull/139) ([spencer-cdw](https://github.com/spencer-cdw)) 37 | - Fixes chrony on ubuntu [\#135](https://github.com/dev-sec/cis-dil-benchmark/pull/135) ([spencer-cdw](https://github.com/spencer-cdw)) 38 | - Use native severspec functions to check uid and gid of files [\#134](https://github.com/dev-sec/cis-dil-benchmark/pull/134) ([spencer-cdw](https://github.com/spencer-cdw)) 39 | - Add ARM64 support [\#133](https://github.com/dev-sec/cis-dil-benchmark/pull/133) ([spencer-cdw](https://github.com/spencer-cdw)) 40 | - Document why audit.rules should include 32 on 64 bit systems [\#132](https://github.com/dev-sec/cis-dil-benchmark/pull/132) ([spencer-cdw](https://github.com/spencer-cdw)) 41 | 42 | ## [0.4.12](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.12) (2022-03-18) 43 | 44 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.11...0.4.12) 45 | 46 | **Closed issues:** 47 | 48 | - `/var/log/btmp` should be included in `group_write_excepts` for CIS 4.2.3 [\#112](https://github.com/dev-sec/cis-dil-benchmark/issues/112) 49 | 50 | **Merged pull requests:** 51 | 52 | - Change linting to Cookstyle [\#120](https://github.com/dev-sec/cis-dil-benchmark/pull/120) ([schurzi](https://github.com/schurzi)) 53 | - cis-dil-benchmark-5.3.4 should match spaces better [\#119](https://github.com/dev-sec/cis-dil-benchmark/pull/119) ([fargburger](https://github.com/fargburger)) 54 | - \(4.2.3\) Add group write exemption for btmp [\#116](https://github.com/dev-sec/cis-dil-benchmark/pull/116) ([bendres97](https://github.com/bendres97)) 55 | 56 | ## [0.4.11](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.11) (2022-01-12) 57 | 58 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.10...0.4.11) 59 | 60 | **Fixed bugs:** 61 | 62 | - cis-dil-benchmark-5.2.5 should allow sshd LogLevel to be INFO or VERBOSE [\#109](https://github.com/dev-sec/cis-dil-benchmark/issues/109) 63 | - fix\(5.2.5\): allow INFO as SSH LogLevel [\#111](https://github.com/dev-sec/cis-dil-benchmark/pull/111) ([deric4](https://github.com/deric4)) 64 | 65 | **Closed issues:** 66 | 67 | - this repo should be labelled inspec [\#110](https://github.com/dev-sec/cis-dil-benchmark/issues/110) 68 | - Inputs set via 'attribute' is now deprecated. [\#81](https://github.com/dev-sec/cis-dil-benchmark/issues/81) 69 | 70 | **Merged pull requests:** 71 | 72 | - use input instead of attribute [\#117](https://github.com/dev-sec/cis-dil-benchmark/pull/117) ([micheelengronne](https://github.com/micheelengronne)) 73 | - add dependency to chef-config for CI [\#108](https://github.com/dev-sec/cis-dil-benchmark/pull/108) ([schurzi](https://github.com/schurzi)) 74 | - use version tag for changelog action [\#107](https://github.com/dev-sec/cis-dil-benchmark/pull/107) ([schurzi](https://github.com/schurzi)) 75 | 76 | ## [0.4.10](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.10) (2021-02-01) 77 | 78 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.9...0.4.10) 79 | 80 | **Closed issues:** 81 | 82 | - cis-dil-benchmark-1.6.3.2: undefined method `positive?' for \#\ [\#105](https://github.com/dev-sec/cis-dil-benchmark/issues/105) 83 | 84 | **Merged pull requests:** 85 | 86 | - revert to using cmp for 1.6.3.2 because of implicit string conversion [\#106](https://github.com/dev-sec/cis-dil-benchmark/pull/106) ([schurzi](https://github.com/schurzi)) 87 | 88 | ## [0.4.9](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.9) (2021-01-29) 89 | 90 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.8...0.4.9) 91 | 92 | **Merged pull requests:** 93 | 94 | - Fix lint [\#104](https://github.com/dev-sec/cis-dil-benchmark/pull/104) ([schurzi](https://github.com/schurzi)) 95 | - GitHub action [\#103](https://github.com/dev-sec/cis-dil-benchmark/pull/103) ([rndmh3ro](https://github.com/rndmh3ro)) 96 | 97 | ## [0.4.8](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.8) (2021-01-08) 98 | 99 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.7...0.4.8) 100 | 101 | **Merged pull requests:** 102 | 103 | - fix\(6.1\): regression expected\_gid [\#100](https://github.com/dev-sec/cis-dil-benchmark/pull/100) ([deric4](https://github.com/deric4)) 104 | 105 | ## [0.4.7](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.7) (2021-01-06) 106 | 107 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.6...0.4.7) 108 | 109 | **Merged pull requests:** 110 | 111 | - Check for `pool` or `server` in chrony.conf [\#101](https://github.com/dev-sec/cis-dil-benchmark/pull/101) ([nvwls](https://github.com/nvwls)) 112 | 113 | ## [0.4.6](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.6) (2021-01-05) 114 | 115 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.5...0.4.6) 116 | 117 | **Closed issues:** 118 | 119 | - RootDistanceMax instead of RootDistanceMaxSec [\#92](https://github.com/dev-sec/cis-dil-benchmark/issues/92) 120 | 121 | **Merged pull requests:** 122 | 123 | - rename RootDistanceMax to RootDistanceMaxSec [\#93](https://github.com/dev-sec/cis-dil-benchmark/pull/93) ([yvespp](https://github.com/yvespp)) 124 | 125 | ## [0.4.5](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.5) (2020-12-30) 126 | 127 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.4...0.4.5) 128 | 129 | **Closed issues:** 130 | 131 | - Travis CI status check failing [\#98](https://github.com/dev-sec/cis-dil-benchmark/issues/98) 132 | - The version on README.md is old [\#94](https://github.com/dev-sec/cis-dil-benchmark/issues/94) 133 | 134 | **Merged pull requests:** 135 | 136 | - Change travis rvm to 2.6 [\#99](https://github.com/dev-sec/cis-dil-benchmark/pull/99) ([micheelengronne](https://github.com/micheelengronne)) 137 | - docs: update README with correct benchmark ver [\#95](https://github.com/dev-sec/cis-dil-benchmark/pull/95) ([deric4](https://github.com/deric4)) 138 | 139 | ## [0.4.4](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.4) (2020-11-30) 140 | 141 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.3...0.4.4) 142 | 143 | **Closed issues:** 144 | 145 | - Any ansible automation to satisfy all these cis checks? [\#87](https://github.com/dev-sec/cis-dil-benchmark/issues/87) 146 | - Any planning on supported the "latest" CiS \(1.1.0\)? [\#58](https://github.com/dev-sec/cis-dil-benchmark/issues/58) 147 | 148 | **Merged pull requests:** 149 | 150 | - CIS DIL Benchmark V2 [\#90](https://github.com/dev-sec/cis-dil-benchmark/pull/90) ([deric4](https://github.com/deric4)) 151 | 152 | ## [0.4.3](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.3) (2020-08-12) 153 | 154 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.2...0.4.3) 155 | 156 | **Merged pull requests:** 157 | 158 | - Feat/updates cinc inspec v4 [\#85](https://github.com/dev-sec/cis-dil-benchmark/pull/85) ([deric4](https://github.com/deric4)) 159 | 160 | ## [0.4.2](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.2) (2020-07-23) 161 | 162 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.1...0.4.2) 163 | 164 | **Merged pull requests:** 165 | 166 | - The release draft references the correct SHA [\#82](https://github.com/dev-sec/cis-dil-benchmark/pull/82) ([micheelengronne](https://github.com/micheelengronne)) 167 | 168 | ## [0.4.1](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.1) (2020-05-19) 169 | 170 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.4.0...0.4.1) 171 | 172 | **Merged pull requests:** 173 | 174 | - align versions [\#80](https://github.com/dev-sec/cis-dil-benchmark/pull/80) ([micheelengronne](https://github.com/micheelengronne)) 175 | 176 | ## [0.4.0](https://github.com/dev-sec/cis-dil-benchmark/tree/0.4.0) (2020-05-19) 177 | 178 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.3.0...0.4.0) 179 | 180 | **Closed issues:** 181 | 182 | - dil-benchmark-1.6.2.2: undefined method `positive?' for \#\ [\#72](https://github.com/dev-sec/cis-dil-benchmark/issues/72) 183 | - WARN: DEPRECATION: The 'default' option for attributes is being replaced by 'value' - please use it instead. attribute name: 'Inspec::Input' [\#69](https://github.com/dev-sec/cis-dil-benchmark/issues/69) 184 | 185 | **Merged pull requests:** 186 | 187 | - automated release [\#79](https://github.com/dev-sec/cis-dil-benchmark/pull/79) ([micheelengronne](https://github.com/micheelengronne)) 188 | - Support wild configs that are tabbed out [\#78](https://github.com/dev-sec/cis-dil-benchmark/pull/78) ([markdchurchill](https://github.com/markdchurchill)) 189 | - SSH config: Allow seconds & minutes config for grace time [\#77](https://github.com/dev-sec/cis-dil-benchmark/pull/77) ([markdchurchill](https://github.com/markdchurchill)) 190 | - Refactor out grub config to profile file [\#76](https://github.com/dev-sec/cis-dil-benchmark/pull/76) ([markdchurchill](https://github.com/markdchurchill)) 191 | - iptables: support conntrack module [\#75](https://github.com/dev-sec/cis-dil-benchmark/pull/75) ([markdchurchill](https://github.com/markdchurchill)) 192 | - Update 3.3 IPv6 to support Amazon Linux 2 [\#74](https://github.com/dev-sec/cis-dil-benchmark/pull/74) ([markdchurchill](https://github.com/markdchurchill)) 193 | - reverse rubocop updates to support ruby versions bundled with InSpec 3 [\#73](https://github.com/dev-sec/cis-dil-benchmark/pull/73) ([chris-rock](https://github.com/chris-rock)) 194 | - pin to inspec 3 [\#71](https://github.com/dev-sec/cis-dil-benchmark/pull/71) ([chris-rock](https://github.com/chris-rock)) 195 | - Inspec 4 warning [\#70](https://github.com/dev-sec/cis-dil-benchmark/pull/70) ([micheelengronne](https://github.com/micheelengronne)) 196 | 197 | ## [0.3.0](https://github.com/dev-sec/cis-dil-benchmark/tree/0.3.0) (2019-02-04) 198 | 199 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.2.0...0.3.0) 200 | 201 | **Closed issues:** 202 | 203 | - Make a release [\#64](https://github.com/dev-sec/cis-dil-benchmark/issues/64) 204 | - Tagging versions for release? [\#51](https://github.com/dev-sec/cis-dil-benchmark/issues/51) 205 | - Why are you using custom linux\_module instead of the Inspec built in kernel\_module? [\#48](https://github.com/dev-sec/cis-dil-benchmark/issues/48) 206 | - How much divergence from CIS DIL Benchmark document is accepted? [\#43](https://github.com/dev-sec/cis-dil-benchmark/issues/43) 207 | 208 | **Merged pull requests:** 209 | 210 | - 0.3.0 [\#65](https://github.com/dev-sec/cis-dil-benchmark/pull/65) ([chris-rock](https://github.com/chris-rock)) 211 | - Ensure /etc/group- /etc/shadow- and /etc/gshadow- match their respect… [\#63](https://github.com/dev-sec/cis-dil-benchmark/pull/63) ([bdwyertech](https://github.com/bdwyertech)) 212 | - Fixes [\#62](https://github.com/dev-sec/cis-dil-benchmark/pull/62) ([bdwyertech](https://github.com/bdwyertech)) 213 | - Change `password` to `passwords` [\#60](https://github.com/dev-sec/cis-dil-benchmark/pull/60) ([jerryaldrichiii](https://github.com/jerryaldrichiii)) 214 | - Update issue templates [\#56](https://github.com/dev-sec/cis-dil-benchmark/pull/56) ([rndmh3ro](https://github.com/rndmh3ro)) 215 | - use inspec's new unified attributes feature [\#55](https://github.com/dev-sec/cis-dil-benchmark/pull/55) ([chris-rock](https://github.com/chris-rock)) 216 | - modify package check to satisfy openjdk dependency [\#53](https://github.com/dev-sec/cis-dil-benchmark/pull/53) ([alval5280](https://github.com/alval5280)) 217 | - allow group write /var/log/wtmp [\#50](https://github.com/dev-sec/cis-dil-benchmark/pull/50) ([alval5280](https://github.com/alval5280)) 218 | 219 | ## [0.2.0](https://github.com/dev-sec/cis-dil-benchmark/tree/0.2.0) (2018-08-26) 220 | 221 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/0.1.0...0.2.0) 222 | 223 | **Closed issues:** 224 | 225 | - Debian uses group 42 \('shadow'\) as group for shadow files [\#31](https://github.com/dev-sec/cis-dil-benchmark/issues/31) 226 | - inspec fails to run due to undefined method 'passwords' [\#5](https://github.com/dev-sec/cis-dil-benchmark/issues/5) 227 | - Wrong modinfo option [\#4](https://github.com/dev-sec/cis-dil-benchmark/issues/4) 228 | - Getting undefined method `split' for nil:NilClass \(NoMethodError\) on MacOS [\#3](https://github.com/dev-sec/cis-dil-benchmark/issues/3) 229 | - Update 6\_2\_user\_and\_group\_settings.rb to mock empty array. [\#1](https://github.com/dev-sec/cis-dil-benchmark/issues/1) 230 | 231 | **Merged pull requests:** 232 | 233 | - 0.2.0 [\#52](https://github.com/dev-sec/cis-dil-benchmark/pull/52) ([chris-rock](https://github.com/chris-rock)) 234 | - Modified controls to use the built in kernel\_module of Inspec [\#49](https://github.com/dev-sec/cis-dil-benchmark/pull/49) ([csabapatyi](https://github.com/csabapatyi)) 235 | - handle potential leading space for umask regex [\#47](https://github.com/dev-sec/cis-dil-benchmark/pull/47) ([veetow](https://github.com/veetow)) 236 | - increase rubocop block length [\#44](https://github.com/dev-sec/cis-dil-benchmark/pull/44) ([chris-rock](https://github.com/chris-rock)) 237 | - Fix shadow user and password deprecations [\#42](https://github.com/dev-sec/cis-dil-benchmark/pull/42) ([timstoop](https://github.com/timstoop)) 238 | - Fix a compare with zero. [\#41](https://github.com/dev-sec/cis-dil-benchmark/pull/41) ([timstoop](https://github.com/timstoop)) 239 | - Also allow pool to be set. [\#39](https://github.com/dev-sec/cis-dil-benchmark/pull/39) ([timstoop](https://github.com/timstoop)) 240 | - Make the 4.1.15 check less strict. [\#38](https://github.com/dev-sec/cis-dil-benchmark/pull/38) ([timstoop](https://github.com/timstoop)) 241 | - According to CIS DIL 1.1.0, wtmp and btmp should be tagged logins. [\#37](https://github.com/dev-sec/cis-dil-benchmark/pull/37) ([timstoop](https://github.com/timstoop)) 242 | - This fixes for the syntax for CIS DIL 4.1.6 to require just one valid describe. [\#36](https://github.com/dev-sec/cis-dil-benchmark/pull/36) ([timstoop](https://github.com/timstoop)) 243 | - Make the check slightly less strict. [\#35](https://github.com/dev-sec/cis-dil-benchmark/pull/35) ([timstoop](https://github.com/timstoop)) 244 | - Fix deprecation warnings. [\#34](https://github.com/dev-sec/cis-dil-benchmark/pull/34) ([timstoop](https://github.com/timstoop)) 245 | - Debian uses group 42 shadow [\#33](https://github.com/dev-sec/cis-dil-benchmark/pull/33) ([timstoop](https://github.com/timstoop)) 246 | - updated regex to account for sha512 not being first option [\#30](https://github.com/dev-sec/cis-dil-benchmark/pull/30) ([michael-c-hoffman](https://github.com/michael-c-hoffman)) 247 | - Adjust modprobe check to remove false positives. [\#28](https://github.com/dev-sec/cis-dil-benchmark/pull/28) ([millerthomasj](https://github.com/millerthomasj)) 248 | - Update umask checks for Centos7 and Amazon Linux. [\#27](https://github.com/dev-sec/cis-dil-benchmark/pull/27) ([millerthomasj](https://github.com/millerthomasj)) 249 | - Update password quality checks for pam. [\#25](https://github.com/dev-sec/cis-dil-benchmark/pull/25) ([millerthomasj](https://github.com/millerthomasj)) 250 | - Allowed MACs should allow for greater security [\#24](https://github.com/dev-sec/cis-dil-benchmark/pull/24) ([millerthomasj](https://github.com/millerthomasj)) 251 | - pin inspec 2.1.0 [\#23](https://github.com/dev-sec/cis-dil-benchmark/pull/23) ([chris-rock](https://github.com/chris-rock)) 252 | - Should check one of cron or crond not both. [\#22](https://github.com/dev-sec/cis-dil-benchmark/pull/22) ([millerthomasj](https://github.com/millerthomasj)) 253 | - Add auditd fixes for Centos7 [\#21](https://github.com/dev-sec/cis-dil-benchmark/pull/21) ([millerthomasj](https://github.com/millerthomasj)) 254 | - Add tcp\_wrappers package for both Centos7 and Amazon Linux. [\#20](https://github.com/dev-sec/cis-dil-benchmark/pull/20) ([millerthomasj](https://github.com/millerthomasj)) 255 | - Add additional filepath for chrony.conf on Centos7. [\#19](https://github.com/dev-sec/cis-dil-benchmark/pull/19) ([millerthomasj](https://github.com/millerthomasj)) 256 | - Ntpd run as user [\#18](https://github.com/dev-sec/cis-dil-benchmark/pull/18) ([millerthomasj](https://github.com/millerthomasj)) 257 | - Centos7 uses grub2 by default, add checks for proper file. [\#17](https://github.com/dev-sec/cis-dil-benchmark/pull/17) ([millerthomasj](https://github.com/millerthomasj)) 258 | - On both Centos7 and latest Amazon Linux ansible auto creates cron ent… [\#16](https://github.com/dev-sec/cis-dil-benchmark/pull/16) ([millerthomasj](https://github.com/millerthomasj)) 259 | - updated regex to detect proper string [\#15](https://github.com/dev-sec/cis-dil-benchmark/pull/15) ([michael-c-hoffman](https://github.com/michael-c-hoffman)) 260 | - Undefinedmethod [\#14](https://github.com/dev-sec/cis-dil-benchmark/pull/14) ([michael-c-hoffman](https://github.com/michael-c-hoffman)) 261 | - changed command for redhat family to modprobe to properly evaluate test [\#10](https://github.com/dev-sec/cis-dil-benchmark/pull/10) ([michael-c-hoffman](https://github.com/michael-c-hoffman)) 262 | - implements inspec check and enables it in travis [\#9](https://github.com/dev-sec/cis-dil-benchmark/pull/9) ([chris-rock](https://github.com/chris-rock)) 263 | - use inspec's os\_env split method [\#8](https://github.com/dev-sec/cis-dil-benchmark/pull/8) ([chris-rock](https://github.com/chris-rock)) 264 | - Passwords to password [\#6](https://github.com/dev-sec/cis-dil-benchmark/pull/6) ([michael-c-hoffman](https://github.com/michael-c-hoffman)) 265 | 266 | ## [0.1.0](https://github.com/dev-sec/cis-dil-benchmark/tree/0.1.0) (2017-08-15) 267 | 268 | [Full Changelog](https://github.com/dev-sec/cis-dil-benchmark/compare/7aa8ff2433d0f01591fedd2633af3883cfc81033...0.1.0) 269 | 270 | 271 | 272 | \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* 273 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'cookstyle' 6 | gem 'highline' 7 | gem 'rack' 8 | gem 'rake' 9 | gem 'rubocop' 10 | 11 | group :tools do 12 | gem 'github_changelog_generator' 13 | gem 'pry-coolline' 14 | end 15 | 16 | source 'https://packagecloud.io/cinc-project/stable' do 17 | gem 'chef-config' 18 | gem 'cinc-auditor-bin' 19 | end 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CIS Distribution Independent Linux Benchmark - InSpec Profile 2 | 3 | ## Description 4 | This profile implements the [CIS Distribution Independent Linux 2.0.0 Benchmark](https://www.cisecurity.org/benchmark/distribution_independent_linux/). 5 | 6 | ## Attributes 7 | 8 | To switch between the CIS profile levels the following attribute can be used: 9 | 10 | * `cis_level: 2` 11 | define which profile level to use, accepted values are `1` and `2`. 12 | 13 | ## License and Author 14 | 15 | * Author:: Kristian Vlaardingerbroek 16 | 17 | Licensed under the Apache License, Version 2.0 (the "License"); 18 | you may not use this file except in compliance with the License. 19 | You may obtain a copy of the License at 20 | 21 | http://www.apache.org/licenses/LICENSE-2.0 22 | 23 | Unless required by applicable law or agreed to in writing, software 24 | distributed under the License is distributed on an "AS IS" BASIS, 25 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 26 | See the License for the specific language governing permissions and 27 | limitations under the License. 28 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'cookstyle' 4 | require 'rake/testtask' 5 | require 'rubocop/rake_task' 6 | 7 | # Rubocop 8 | desc 'Run Rubocop lint checks' 9 | task :rubocop do 10 | RuboCop::RakeTask.new 11 | end 12 | 13 | RuboCop::RakeTask.new(:cookstyle) do |task| 14 | task.options << '--display-cop-names' 15 | end 16 | 17 | # lint the project 18 | desc 'Run robocop linter' 19 | task lint: [:rubocop] 20 | 21 | # run tests 22 | task default: [:lint, 'test:check'] 23 | 24 | namespace :test do 25 | # run inspec check to verify that the profile is properly configured 26 | task :check do 27 | require 'inspec' 28 | puts "Checking profile with InSpec Version: #{Inspec::VERSION}" 29 | profile = Inspec::Profile.for_target('.', backend: Inspec::Backend.create(Inspec::Config.mock)) 30 | pp profile.check 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /controls/1_2_configure_software_updates.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '1.2 Configure Software Updates' 21 | 22 | control 'cis-dil-benchmark-1.2.1' do 23 | title 'Ensure package manager repositories are configured' 24 | desc "Systems need to have package manager repositories configured to ensure they receive the latest patches and updates.\n\nRationale: If a system's package repositories are misconfigured important patches may not be identified or a rogue repository could introduce compromised software." 25 | impact 0.0 26 | 27 | tag cis: 'distribution-independent-linux:1.2.1' 28 | tag level: 1 29 | 30 | describe 'cis-dil-benchmark-1.2.1' do 31 | skip 'Not implemented' 32 | end 33 | end 34 | 35 | control 'cis-dil-benchmark-1.2.2' do 36 | title 'Ensure GPG keys are configured' 37 | desc "Most packages managers implement GPG key signing to verify package integrity during installation.\n\nRationale: It is important to ensure that updates are obtained from a valid source to protect against spoofing that could lead to the inadvertent installation of malware on the system." 38 | impact 0.0 39 | 40 | tag cis: 'distribution-independent-linux:1.2.2' 41 | tag level: 1 42 | 43 | describe 'cis-dil-benchmark-1.2.2' do 44 | skip 'Not implemented' 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /controls/1_3_filesystem_integrity_checking.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | # 20 | 21 | title '1.3 Filesystem Integrity Checking' 22 | 23 | control 'cis-dil-benchmark-1.3.1' do 24 | title 'Ensure AIDE is installed' 25 | desc "AIDE takes a snapshot of filesystem state including modification times, permissions, and file hashes which can then be used to compare against the current state of the filesystem to detect modifications to the system.\n\nRationale: By monitoring the filesystem state compromised files can be detected to prevent or limit the exposure of accidental or malicious misconfigurations or modified binaries." 26 | impact 1.0 27 | 28 | tag cis: 'distribution-independent-linux:1.3.1' 29 | tag level: 1 30 | 31 | describe.one do 32 | describe package('aide') do 33 | it { should be_installed } 34 | end 35 | 36 | describe command('aide') do 37 | it { should exist } 38 | end 39 | end 40 | end 41 | 42 | control 'cis-dil-benchmark-1.3.2' do 43 | title 'Ensure filesystem integrity is regularly checked' 44 | desc "Periodic checking of the filesystem integrity is needed to detect changes to the filesystem.\n\nRationale: Periodic file checking allows the system administrator to determine on a regular basis if critical files have been changed in an unauthorized fashion." 45 | impact 1.0 46 | 47 | tag cis: 'distribution-independent-linux:1.3.2' 48 | tag level: 1 49 | 50 | describe.one do 51 | %w(/var/spool/cron/crontabs/root /var/spool/cron/root /etc/crontab).each do |f| 52 | describe file(f) do 53 | its('content') { should match(/aide (--check|-C)/) } 54 | end 55 | end 56 | 57 | %w(cron.d cron.hourly cron.daily cron.weekly cron.monthly).each do |f| 58 | command("find /etc/#{f} -type f").stdout.split.each do |entry| 59 | describe file(entry) do 60 | its('content') { should match(/aide (--check|-C)/) } 61 | end 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /controls/1_4_secure_boot_settings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '1.4 Secure Boot Settings' 21 | 22 | control 'cis-dil-benchmark-1.4.1' do 23 | title 'Ensure permissions on bootloader config are configured' 24 | desc "The grub configuration file contains information on boot settings and passwords for unlocking boot options. The grub configuration is usually grub.cfg stored in /boot/grub.\n\nRationale: Setting the permissions to read and write for root only prevents non-root users from seeing the boot parameters or changing them. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them." 25 | impact 1.0 26 | 27 | tag cis: 'distribution-independent-linux:1.4.1' 28 | tag level: 1 29 | 30 | describe.one do 31 | grub_conf.locations.each do |f| 32 | describe file(f) do 33 | it { should exist } 34 | it { should_not be_readable.by 'group' } 35 | it { should_not be_writable.by 'group' } 36 | it { should_not be_executable.by 'group' } 37 | it { should_not be_readable.by 'other' } 38 | it { should_not be_writable.by 'other' } 39 | it { should_not be_executable.by 'other' } 40 | it { should be_grouped_into 'root' } 41 | it { should be_owned_by 'root' } 42 | end 43 | end 44 | end 45 | end 46 | 47 | control 'cis-dil-benchmark-1.4.2' do 48 | title 'Ensure bootloader password is set' 49 | desc "Setting the boot loader password will require that anyone rebooting the system must enter a password before being able to set command line boot parameters\n\nRationale: Requiring a boot password upon execution of the boot loader will prevent an unauthorized user from entering boot parameters or changing the boot partition. This prevents users from weakening security (e.g. turning off SELinux at boot time)." 50 | impact 1.0 51 | 52 | tag cis: 'distribution-independent-linux:1.4.2' 53 | tag level: 1 54 | 55 | describe.one do 56 | grub_conf.locations.each do |f| 57 | describe file(f) do 58 | its(:content) { should match(/^set superusers/) } 59 | its(:content) { should match(/^password/) } 60 | end 61 | end 62 | end 63 | end 64 | 65 | control 'cis-dil-benchmark-1.4.3' do 66 | title 'Ensure authentication required for single user mode' 67 | desc "Single user mode is used for recovery when the system detects an issue during boot or by manual selection from the bootloader.\n\nRationale: Requiring authentication in single user mode prevents an unauthorized user from rebooting the system into single user to gain root privileges without credentials." 68 | impact 1.0 69 | 70 | tag cis: 'distribution-independent-linux:1.4.3' 71 | tag level: 1 72 | 73 | describe.one do 74 | describe shadow.users('root') do 75 | its(:passwords) { should_not include('*') } 76 | its(:passwords) { should_not include('!') } 77 | end 78 | 79 | describe file('/etc/inittab') do 80 | its(:content) { should match(%r{^~~:S:respawn:/sbin/sulogin}) } 81 | end 82 | 83 | describe file('/etc/sysconfig/init') do 84 | its(:content) { should match(%r{^SINGLE=/sbin/sulogin$}) } 85 | end 86 | end 87 | end 88 | 89 | control 'cis-dil-benchmark-1.4.4' do 90 | title 'Ensure interactive boot is not enabled' 91 | desc "Interactive boot allows console users to interactively select which services start on boot. Not all distributions support this capability.\nThe PROMPT_FOR_CONFIRM option provides console users the ability to interactively boot the system and select which services to start on boot .\n\nRationale: Turn off the PROMPT_FOR_CONFIRM option on the console to prevent console users from potentially overriding established security settings." 92 | impact 0.0 93 | 94 | tag cis: 'distribution-independent-linux:1.4.4' 95 | tag level: 1 96 | 97 | if file('/etc/sysconfig/boot').exist? 98 | describe file('/etc/sysconfig/boot') do 99 | its(:content) { should match(/^PROMPT_FOR_CONFIRM="no"$/) } 100 | end 101 | else 102 | describe 'cis-dil-benchmark-1.4.4' do 103 | skip 'Not implemented' 104 | end 105 | end 106 | end 107 | -------------------------------------------------------------------------------- /controls/1_5_additional_process_hardening.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '1.5 Additional Process Hardening' 21 | 22 | uname_machine = command('uname -m').stdout.strip 23 | 24 | control 'cis-dil-benchmark-1.5.1' do 25 | title 'Ensure core dumps are restricted' 26 | desc "A core dump is the memory of an executable program. It is generally used to determine why a program aborted. It can also be used to glean confidential information from a core file. The system provides the ability to set a soft limit for core dumps, but this can be overridden by the user.\n\nRationale: Setting a hard limit on core dumps prevents users from overriding the soft variable. If core dumps are required, consider setting limits for user groups (see limits.conf(5)). In addition, setting the fs.suid_dumpable variable to 0 will prevent setuid programs from dumping core." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:1.5.1' 30 | tag level: 1 31 | 32 | describe.one do 33 | describe file('/etc/security/limits.conf') do 34 | its(:content) { should match(/^\s*\*\s+hard\s+core\s+0\s*(?:#.*)?$/) } 35 | end 36 | 37 | command('find /etc/security/limits.d -type f').stdout.split.each do |f| 38 | describe file(f) do 39 | its(:content) { should match(/^\s*\*\s+hard\s+core\s+0\s*(?:#.*)?$/) } 40 | end 41 | end 42 | end 43 | 44 | describe kernel_parameter('fs.suid_dumpable') do 45 | its(:value) { should eq 0 } 46 | end 47 | end 48 | 49 | control 'cis-dil-benchmark-1.5.2' do 50 | title 'Ensure XD/NX support is enabled' 51 | desc "Recent processors in the x86 family support the ability to prevent code execution on a per memory page basis. Generically and on AMD processors, this ability is called No Execute (NX), while on Intel processors it is called Execute Disable (XD). This ability can help prevent exploitation of buffer overflow vulnerabilities and should be activated whenever possible. Extra steps must be taken to ensure that this protection is enabled, particularly on 32-bit x86 systems. Other processors, such as Itanium and POWER, have included such support since inception and the standard kernel for those platforms supports the feature.\n\nRationale: Enabling any feature that can protect against buffer overflow attacks enhances the security of the system." 52 | impact 0.0 53 | 54 | tag cis: 'distribution-independent-linux:1.5.2' 55 | tag level: 1 56 | 57 | if uname_machine == 'i386' || uname_machine == 'i686' || uname_machine == 'x86_64' 58 | describe command('dmesg | grep NX') do 59 | its(:stdout) { should match(/NX \(Execute Disable\) protection: active/) } 60 | end 61 | else 62 | describe 'cis-dil-benchmark-1.5.2' do 63 | skip 'Not implemented' 64 | end 65 | end 66 | end 67 | 68 | control 'cis-dil-benchmark-1.5.3' do 69 | title 'Ensure address space layout randomization (ASLR) is enabled' 70 | desc "Address space layout randomization (ASLR) is an exploit mitigation technique which randomly arranges the address space of key data areas of a process.\n\nRationale: Randomly placing virtual memory regions will make it difficult to write memory page exploits as the memory placement will be consistently shifting." 71 | impact 1.0 72 | 73 | tag cis: 'distribution-independent-linux:1.5.3' 74 | tag level: 1 75 | 76 | describe kernel_parameter('kernel.randomize_va_space') do 77 | its(:value) { should eq 2 } 78 | end 79 | end 80 | 81 | control 'cis-dil-benchmark-1.5.4' do 82 | title 'Ensure prelink is disabled' 83 | desc "prelink is a program that modifies ELF shared libraries and ELF dynamically linked binaries in such a way that the time needed for the dynamic linker to perform relocations at startup significantly decreases.\n\nRationale: The prelinking feature can interfere with the operation of AIDE, because it changes binaries. Prelinking can also increase the vulnerability of the system if a malicious user is able to compromise a common library such as libc." 84 | impact 1.0 85 | 86 | tag cis: 'distribution-independent-linux:1.5.4' 87 | tag level: 1 88 | 89 | describe.one do 90 | describe package('prelink') do 91 | it { should_not be_installed } 92 | end 93 | 94 | describe command('prelink') do 95 | it { should_not exist } 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /controls/1_6_mandatory_access_control.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | cis_level = input('cis_level') 21 | 22 | title '1.6 Mandatory Access Control' 23 | 24 | control 'cis-dil-benchmark-1.6.1.1' do 25 | title 'Ensure SELinux or AppArmor are installed' 26 | desc "SELinux and AppArmor provide Mandatory Access Controls.\n\nRationale: Without a Mandatory Access Control system installed only the default Discretionary Access Control system will be available." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:1.6.1.1' 30 | tag level: 2 31 | 32 | describe.one do 33 | %w(libselinux libselinux1 apparmor).each do |p| 34 | describe package(p) do 35 | it { should be_installed } 36 | end 37 | end 38 | end 39 | 40 | only_if { cis_level == 2 } 41 | end 42 | 43 | control 'cis-dil-benchmark-1.6.2.1' do 44 | title 'Ensure SELinux is not disabled in bootloader configuration' 45 | desc "Configure SELINUX to be enabled at boot time and verify that it has not been overwritten by the grub boot parameters.\n\nRationale: SELinux must be enabled at boot time in your grub configuration to ensure that the controls it provides are not overridden." 46 | impact 1.0 47 | 48 | tag cis: 'distribution-independent-linux:1.6.2.1' 49 | tag level: 2 50 | 51 | describe.one do 52 | %w(/boot/grub2/grub.cfg /boot/grub/menu.lst).each do |f| 53 | describe file(f) do 54 | its('content') { should_not match /selinux=0/ } 55 | its('content') { should_not match /enforcing=0/ } 56 | end 57 | end 58 | end 59 | 60 | only_if { cis_level == 2 } 61 | end 62 | 63 | control 'cis-dil-benchmark-1.6.2.2' do 64 | title 'Ensure the SELinux state is enforcing' 65 | desc "Set SELinux to enable when the system is booted.\n\nRationale: SELinux must be enabled at boot time in to ensure that the controls it provides are in effect at all times." 66 | impact 1.0 67 | 68 | tag cis: 'distribution-independent-linux:1.6.2.2' 69 | tag level: 2 70 | 71 | describe file('/etc/selinux/config') do 72 | its('content') { should match /^SELINUX=enforcing\s*(?:#.*)?$/ } 73 | end 74 | 75 | describe command('sestatus') do 76 | its('stdout') { should match /SELinux status:\s+enabled/ } 77 | its('stdout') { should match /Current mode:\s+enforcing/ } 78 | its('stdout') { should match /Mode from config file:\s+enforcing/ } 79 | end 80 | 81 | only_if { cis_level == 2 } 82 | end 83 | 84 | control 'cis-dil-benchmark-1.6.2.3' do 85 | title 'Ensure SELinux policy is configured' 86 | desc "Configure SELinux to meet or exceed the default targeted policy, which constrains daemons and system software only.\n\nRationale: Security configuration requirements vary from site to site. Some sites may mandate a policy that is stricter than the default policy, which is perfectly acceptable. This item is intended to ensure that at least the default recommendations are met." 87 | impact 1.0 88 | 89 | tag cis: 'distribution-independent-linux:1.6.2.3' 90 | tag level: 2 91 | 92 | describe file('/etc/selinux/config') do 93 | its('content') { should match /^SELINUXTYPE=(targeted|mls)\s*(?:#.*)?$/ } 94 | end 95 | 96 | describe command('sestatus') do 97 | its('stdout') { should match /(Loaded policy name|Policy from config file):\s+(targeted|mls)/ } 98 | end 99 | 100 | only_if { cis_level == 2 } 101 | end 102 | 103 | control 'cis-dil-benchmark-1.6.2.4' do 104 | title 'Ensure SETroubleshoot is not installed' 105 | desc "The SETroubleshoot service notifies desktop users of SELinux denials through a user- friendly interface. The service provides important information around configuration errors, unauthorized intrusions, and other potential errors.\n\nRationale: The SETroubleshoot service is an unnecessary daemon to have running on a server, especially if X Windows is disabled." 106 | impact 1.0 107 | 108 | tag cis: 'distribution-independent-linux:1.6.2.4' 109 | tag level: 2 110 | 111 | describe package('setroubleshoot') do 112 | it { should_not be_installed } 113 | end 114 | 115 | describe command('setroubleshoot') do 116 | it { should_not exist } 117 | end 118 | 119 | only_if { cis_level == 2 } 120 | end 121 | 122 | control 'cis-dil-benchmark-1.6.2.5' do 123 | title 'Ensure the MCS Translation Service (mcstrans) is not installed' 124 | desc "The mcstransd daemon provides category label information to client processes requesting information. The label translations are defined in /etc/selinux/targeted/setrans.conf\n\nRationale: Since this service is not used very often, remove it to reduce the amount of potentially vulnerable code running on the system." 125 | impact 1.0 126 | 127 | tag cis: 'distribution-independent-linux:1.6.2.5' 128 | tag level: 2 129 | 130 | describe package('mcstrans') do 131 | it { should_not be_installed } 132 | end 133 | 134 | describe command('mcstransd') do 135 | it { should_not exist } 136 | end 137 | 138 | only_if { cis_level == 2 } 139 | end 140 | 141 | control 'cis-dil-benchmark-1.6.2.6' do 142 | title 'Ensure no unconfined daemons exist' 143 | desc "Daemons that are not defined in SELinux policy will inherit the security context of their parent process.\n\nRationale: Since daemons are launched and descend from the init process, they will inherit the security context label initrc_t. This could cause the unintended consequence of giving the process more permission than it requires." 144 | impact 1.0 145 | 146 | tag cis: 'distribution-independent-linux:1.6.2.6' 147 | tag level: 2 148 | 149 | describe command('ps -eZ | grep -E "initrc" | grep -E -v -w "tr|ps|grep|bash|awk" | tr \':\' \' \' | awk \'{ print $NF }\'') do 150 | its('stdout') { should eq '' } 151 | end 152 | 153 | only_if { cis_level == 2 } 154 | end 155 | 156 | control 'cis-dil-benchmark-1.6.3.1' do 157 | title 'Ensure AppArmor is not disabled in bootloader configuration' 158 | desc "Configure AppArmor to be enabled at boot time and verify that it has not been overwritten by the bootloader boot parameters.\n\nRationale: AppArmor must be enabled at boot time in your bootloader configuration to ensure that the controls it provides are not overridden." 159 | impact 1.0 160 | 161 | tag cis: 'distribution-independent-linux:1.6.3.1' 162 | tag level: 2 163 | 164 | only_if { cis_level == 2 && package('apparmor').installed? } 165 | 166 | describe.one do 167 | grub_conf.locations.each do |f| 168 | describe file(f) do 169 | its('content') { should_not match /apparmor=0/ } 170 | end 171 | end 172 | end 173 | end 174 | 175 | control 'cis-dil-benchmark-1.6.3.2' do 176 | title 'Ensure all AppArmor Profiles are enforcing' 177 | desc "AppArmor profiles define what resources applications are able to access.\n\nRationale: Security configuration requirements vary from site to site. Some sites may mandate a policy that is stricter than the default policy, which is perfectly acceptable. This item is intended to ensure that any policies that exist on the system are activated." 178 | impact 1.0 179 | 180 | tag cis: 'distribution-independent-linux:1.6.3.2' 181 | tag level: 2 182 | 183 | only_if { cis_level == 2 && package('apparmor').installed? } 184 | 185 | describe command('apparmor_status --profiled') do 186 | its('stdout') { should cmp > 0 } 187 | end 188 | 189 | describe command('apparmor_status --complaining') do 190 | its('stdout') { should cmp 0 } 191 | end 192 | 193 | describe command('apparmor_status') do 194 | its('stdout') { should match(/0 processes are unconfined/) } 195 | end 196 | end 197 | -------------------------------------------------------------------------------- /controls/1_7_warning_banners.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '1.7 Warning Banners' 21 | 22 | control 'cis-dil-benchmark-1.7.1.1' do 23 | title 'Ensure message of the day is configured properly' 24 | desc "The contents of the /etc/motd file are displayed to users after login and function as a message of the day for authenticated users.\nUnix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. This information can be useful to developers who are developing software for a particular OS platform. If mingetty(8) supports the following options, they display operating system information: \n\\m - machine architecture \\r - operating system release \\s - operating system name \\v - operating system version\n\nRationale: Warning messages inform users who are attempting to login to the system of their legal status regarding the system and must include the name of the organization that owns the system and any monitoring policies that are in place. Displaying OS and patch level information in login banners also has the side effect of providing detailed system information to attackers attempting to target specific exploits of a system. Authorized users can easily get this information by running the \"uname -a\" command once they have logged in." 25 | impact 1.0 26 | 27 | tag cis: 'distribution-independent-linux:1.7.1.1' 28 | tag level: 1 29 | 30 | describe command('grep -E -i \'(\\v|\\r|\\m|\\s|$(grep \'^ID=\' /etc/os-release | cut -d= -f2 | sed -e \'s/"//g\'))\' /etc/motd') do 31 | its('stdout') { should eq '' } 32 | end 33 | end 34 | 35 | control 'cis-dil-benchmark-1.7.1.2' do 36 | title 'Ensure local login warning banner is configured properly' 37 | desc "The contents of the /etc/issue file are displayed to users prior to login for local terminals.\nUnix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. This information can be useful to developers who are developing software for a particular OS platform. If mingetty(9) supports the following options, they display operating system information: \\m - machine architecture ( uname -m ) \\r - operating system release ( uname -r ) \\s - operating system name \\v - operating system version ( uname -v )\n\nRationale: Warning messages inform users who are attempting to login to the system of their legal status regarding the system and must include the name of the organization that owns the system and any monitoring policies that are in place. Displaying OS and patch level information in login banners also has the side effect of providing detailed system information to attackers attempting to target specific exploits of a system. Authorized users can easily get this information by running the \"uname -a\" command once they have logged in." 38 | impact 0.0 39 | 40 | tag cis: 'distribution-independent-linux:1.7.1.2' 41 | tag level: 1 42 | 43 | describe command('grep -E -i \'(\\v|\\r|\\m|\\s|$(grep \'^ID=\' /etc/os-release | cut -d= -f2 | sed -e \'s/"//g\'))\' /etc/issue') do 44 | its('stdout') { should eq '' } 45 | end 46 | end 47 | 48 | control 'cis-dil-benchmark-1.7.1.3' do 49 | title 'Ensure remote login warning banner is configured properly' 50 | desc "The contents of the /etc/issue.net file are displayed to users prior to login for remote connections from configured services.\nUnix-based systems have typically displayed information about the OS release and patch level upon logging in to the system. This information can be useful to developers who are developing software for a particular OS platform. If mingetty(8) supports the following options, they display operating system information: \\m - machine architecture ( uname -m ) \\r - operating system release ( uname -r ) \\s - operating system name \\v - operating system version ( uname -v )\n\nRationale: Warning messages inform users who are attempting to login to the system of their legal status regarding the system and must include the name of the organization that owns the system and any monitoring policies that are in place. Displaying OS and patch level information in login banners also has the side effect of providing detailed system information to attackers attempting to target specific exploits of a system. Authorized users can easily get this information by running the \"uname -a\" command once they have logged in." 51 | impact 0.0 52 | 53 | tag cis: 'distribution-independent-linux:1.7.1.3' 54 | tag level: 1 55 | 56 | describe command('grep -E -i \'(\\v|\\r|\\m|\\s|$(grep \'^ID=\' /etc/os-release | cut -d= -f2 | sed -e \'s/"//g\'))\' /etc/issue.net') do 57 | its('stdout') { should eq '' } 58 | end 59 | end 60 | 61 | control 'cis-dil-benchmark-1.7.1.4' do 62 | title 'Ensure permissions on /etc/motd are configured' 63 | desc "The contents of the /etc/motd file are displayed to users after login and function as a message of the day for authenticated users.\n\nRationale: If the /etc/motd file does not have the correct ownership it could be modified by unauthorized users with incorrect or misleading information." 64 | impact 0.0 65 | 66 | tag cis: 'distribution-independent-linux:1.7.1.4' 67 | tag level: 1 68 | 69 | describe file('/etc/motd') do 70 | its('group') { should eq 'root' } 71 | its('owner') { should eq 'root' } 72 | its('mode') { should cmp '0644' } 73 | end 74 | end 75 | 76 | control 'cis-dil-benchmark-1.7.1.5' do 77 | title 'Ensure permissions on /etc/issue are configured' 78 | desc "The contents of the /etc/issue file are displayed to users prior to login for local terminals.\n\nRationale: If the /etc/issue file does not have the correct ownership it could be modified by unauthorized users with incorrect or misleading information." 79 | impact 1.0 80 | 81 | tag cis: 'distribution-independent-linux:1.7.1.5' 82 | tag level: 1 83 | 84 | describe file('/etc/issue') do 85 | its('group') { should eq 'root' } 86 | its('owner') { should eq 'root' } 87 | its('mode') { should cmp '0644' } 88 | end 89 | end 90 | 91 | control 'cis-dil-benchmark-1.7.1.6' do 92 | title 'Ensure permissions on /etc/issue.net are configured' 93 | desc "The contents of the /etc/issue.net file are displayed to users prior to login for remote connections from configured services.\n\nRationale: If the /etc/issue.net file does not have the correct ownership it could be modified by unauthorized users with incorrect or misleading information." 94 | impact 0.0 95 | 96 | tag cis: 'distribution-independent-linux:1.7.1.6' 97 | tag level: 1 98 | 99 | describe file('/etc/issue.net') do 100 | its('group') { should eq 'root' } 101 | its('owner') { should eq 'root' } 102 | its('mode') { should cmp '0644' } 103 | end 104 | end 105 | 106 | control 'cis-dil-benchmark-1.7.2' do 107 | title 'Ensure GDM login banner is configured' 108 | desc "GDM is the GNOME Display Manager which handles graphical login for GNOME based systems.\n\nRationale: Warning messages inform users who are attempting to login to the system of their legal status regarding the system and must include the name of the organization that owns the system and any monitoring policies that are in place." 109 | impact 1.0 110 | 111 | tag cis: 'distribution-independent-linux:1.7.2' 112 | tag level: 1 113 | 114 | only_if do 115 | package('gdm').installed? 116 | end 117 | 118 | describe file('/etc/dconf/profile/gdm') do 119 | its(:content) { should match(/^user-db:user$/) } 120 | its(:content) { should match(/^system-db:gdm$/) } 121 | its(:content) { should match(%r{^file-db:/usr/share/gdm/greeter-dconf-defaults$}) } 122 | end 123 | 124 | describe file('/etc/dconf/db/gdm.d/01-banner-message') do 125 | its(:content) { should match(/^banner-message-enable=true$/) } 126 | its(:content) { should match(/^banner-message-text='.+'$/) } 127 | end 128 | end 129 | -------------------------------------------------------------------------------- /controls/1_8_ensure_patches.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '1.8 Ensure patches' 21 | 22 | control 'cis-dil-benchmark-1.8' do 23 | title 'Ensure updates, patches, and additional security software are installed' 24 | desc "Periodically patches are released for included software either due to security flaws or to include additional functionality.\n\nRationale: Newer patches may contain security enhancements that would not be available through the latest full update. As a result, it is recommended that the latest software patches be used to take advantage of the latest functionality. As with any software installation, organizations need to determine if a given update meets their requirements and verify the compatibility and supportability of any additional software against the update revision that is selected." 25 | impact 0.0 26 | 27 | tag cis: 'distribution-independent-linux:1.8' 28 | tag level: 1 29 | 30 | describe 'cis-dil-benchmark-1.8' do 31 | skip 'Not implemented' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /controls/2_1_inetd_services.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '2.1 inetd Services' 21 | 22 | control 'cis-dil-benchmark-2.1.1' do 23 | title 'Ensure chargen services are not enabled' 24 | desc "chargen is a network service that responds with 0 to 512 ASCII characters for each connection it receives. This service is intended for debugging and testing purposes. It is recommended that this service be disabled.\n\nRationale: Disabling this service will reduce the remote attack surface of the system." 25 | impact 1.0 26 | 27 | tag cis: 'distribution-independent-linux:2.1.1' 28 | tag level: 1 29 | 30 | only_if('inetd/xinetd config exists') do 31 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 32 | end 33 | 34 | describe xinetd_conf.services('chargen') do 35 | it { should be_disabled } 36 | end 37 | 38 | describe inetd_conf do 39 | its(:chargen) { should eq nil } 40 | end 41 | 42 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 43 | describe inetd_conf(entry) do 44 | its(:chargen) { should eq nil } 45 | end 46 | end 47 | end 48 | 49 | control 'cis-dil-benchmark-2.1.2' do 50 | title 'Ensure daytime services are not enabled' 51 | desc "daytime is a network service that responds with the server's current date and time. This service is intended for debugging and testing purposes. It is recommended that this service be disabled.\n\nRationale: Disabling this service will reduce the remote attack surface of the system." 52 | impact 1.0 53 | 54 | tag cis: 'distribution-independent-linux:2.1.2' 55 | tag level: 1 56 | 57 | only_if('inetd/xinetd config exists') do 58 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 59 | end 60 | 61 | describe xinetd_conf.services('daytime') do 62 | it { should be_disabled } 63 | end 64 | 65 | describe inetd_conf do 66 | its(:daytime) { should eq nil } 67 | end 68 | 69 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 70 | describe inetd_conf(entry) do 71 | its(:daytime) { should eq nil } 72 | end 73 | end 74 | end 75 | 76 | control 'cis-dil-benchmark-2.1.3' do 77 | title 'Ensure discard services are not enabled' 78 | desc "discard is a network service that simply discards all data it receives. This service is intended for debugging and testing purposes. It is recommended that this service be disabled.\n\nRationale: Disabling this service will reduce the remote attack surface of the system." 79 | impact 1.0 80 | 81 | tag cis: 'distribution-independent-linux:2.1.3' 82 | tag level: 1 83 | 84 | only_if('inetd/xinetd config exists') do 85 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 86 | end 87 | 88 | describe xinetd_conf.services('discard') do 89 | it { should be_disabled } 90 | end 91 | 92 | describe inetd_conf do 93 | its(:discard) { should eq nil } 94 | end 95 | 96 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 97 | describe inetd_conf(entry) do 98 | its(:discard) { should eq nil } 99 | end 100 | end 101 | end 102 | 103 | control 'cis-dil-benchmark-2.1.4' do 104 | title 'Ensure echo services are not enabled' 105 | desc "echo is a network service that responds to clients with the data sent to it by the client. This service is intended for debugging and testing purposes. It is recommended that this service be disabled.\n\nRationale: Disabling this service will reduce the remote attack surface of the system." 106 | impact 1.0 107 | 108 | tag cis: 'distribution-independent-linux:2.1.4' 109 | tag level: 1 110 | 111 | only_if('inetd/xinetd config exists') do 112 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 113 | end 114 | 115 | describe xinetd_conf.services('echo') do 116 | it { should be_disabled } 117 | end 118 | 119 | describe inetd_conf do 120 | its(:echo) { should eq nil } 121 | end 122 | 123 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 124 | describe inetd_conf(entry) do 125 | its(:echo) { should eq nil } 126 | end 127 | end 128 | end 129 | 130 | control 'cis-dil-benchmark-2.1.5' do 131 | title 'Ensure time services are not enabled' 132 | desc "time is a network service that responds with the server's current date and time as a 32 bit integer. This service is intended for debugging and testing purposes. It is recommended that this service be disabled.\n\nRationale: Disabling this service will reduce the remote attack surface of the system." 133 | impact 1.0 134 | 135 | tag cis: 'distribution-independent-linux:2.1.5' 136 | tag level: 1 137 | 138 | only_if('inetd/xinetd config exists') do 139 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 140 | end 141 | 142 | describe xinetd_conf.services('time') do 143 | it { should be_disabled } 144 | end 145 | 146 | describe inetd_conf do 147 | its(:time) { should eq nil } 148 | end 149 | 150 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 151 | describe inetd_conf(entry) do 152 | its(:time) { should eq nil } 153 | end 154 | end 155 | end 156 | 157 | control 'cis-dil-benchmark-2.1.6' do 158 | title 'Ensure rsh server is not enabled' 159 | desc "The Berkeley rsh-server (rsh, rlogin, rexec) package contains legacy services that exchange credentials in clear-text.\n\nRationale: These legacy services contain numerous security exposures and have been replaced with the more secure SSH package." 160 | impact 1.0 161 | 162 | tag cis: 'distribution-independent-linux:2.1.6' 163 | tag level: 1 164 | 165 | only_if('inetd/xinetd config exists') do 166 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 167 | end 168 | 169 | %w(shell login exec rsh rlogin rexec).each do |s| 170 | describe xinetd_conf.services(s) do 171 | it { should be_disabled } 172 | end 173 | 174 | describe inetd_conf do 175 | its(s) { should eq nil } 176 | end 177 | 178 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 179 | describe inetd_conf(entry) do 180 | its(s) { should eq nil } 181 | end 182 | end 183 | end 184 | end 185 | 186 | control 'cis-dil-benchmark-2.1.7' do 187 | title 'Ensure talk server is not enabled' 188 | desc "The talk software makes it possible for users to send and receive messages across systems through a terminal session. The talk client (allows initiate of talk sessions) is installed by default.\n\nRationale: The software presents a security risk as it uses unencrypted protocols for communication." 189 | impact 1.0 190 | 191 | tag cis: 'distribution-independent-linux:2.1.7' 192 | tag level: 1 193 | 194 | only_if('inetd/xinetd config exists') do 195 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 196 | end 197 | 198 | %w(talk ntalk).each do |s| 199 | describe xinetd_conf.services(s) do 200 | it { should be_disabled } 201 | end 202 | 203 | describe inetd_conf do 204 | its(s) { should eq nil } 205 | end 206 | 207 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 208 | describe inetd_conf(entry) do 209 | its(s) { should eq nil } 210 | end 211 | end 212 | end 213 | end 214 | 215 | control 'cis-dil-benchmark-2.1.8' do 216 | title 'Ensure telnet server is not enabled' 217 | desc "The telnet-server package contains the telnet daemon, which accepts connections from users from other systems via the telnet protocol.\n\nRationale: The telnet protocol is insecure and unencrypted. The use of an unencrypted transmission medium could allow a user with access to sniff network traffic the ability to steal credentials. The ssh package provides an encrypted session and stronger security." 218 | impact 1.0 219 | 220 | tag cis: 'distribution-independent-linux:2.1.8' 221 | tag level: 1 222 | 223 | only_if('inetd/xinetd config exists') do 224 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 225 | end 226 | 227 | describe xinetd_conf.services('telnet') do 228 | it { should be_disabled } 229 | end 230 | 231 | describe inetd_conf do 232 | its(:telnet) { should eq nil } 233 | end 234 | 235 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 236 | describe inetd_conf(entry) do 237 | its(:telnet) { should eq nil } 238 | end 239 | end 240 | end 241 | 242 | control 'cis-dil-benchmark-2.1.9' do 243 | title 'Ensure tftp server is not enabled' 244 | desc "Trivial File Transfer Protocol (TFTP) is a simple file transfer protocol, typically used to automatically transfer configuration or boot machines from a boot server. The packages tftp and atftp are both used to define and support a TFTP server.\n\nRationale: TFTP does not support authentication nor does it ensure the confidentiality or integrity of data. It is recommended that TFTP be removed, unless there is a specific need for TFTP. In that case, extreme caution must be used when configuring the services." 245 | impact 1.0 246 | 247 | tag cis: 'distribution-independent-linux:2.1.9' 248 | tag level: 1 249 | 250 | only_if('inetd/xinetd config exists') do 251 | file('/etc/xinetd.conf').exist? || file('/etc/inetd.conf').exist? 252 | end 253 | 254 | describe xinetd_conf.services('tftp') do 255 | it { should be_disabled } 256 | end 257 | 258 | describe inetd_conf do 259 | its(:tftp) { should eq nil } 260 | end 261 | 262 | command('find /etc/inetd.d -type f').stdout.split.each do |entry| 263 | describe inetd_conf(entry) do 264 | its(:tftp) { should eq nil } 265 | end 266 | end 267 | end 268 | 269 | control 'cis-dil-benchmark-2.1.10' do 270 | title 'Ensure xinetd is not enabled' 271 | desc "The eXtended InterNET Daemon (xinetd) is an open source super daemon that replaced the original inetd daemon. The xinetd daemon listens for well known services and dispatches the appropriate daemon to properly respond to service requests.\n\nRationale: If there are no xinetd services required, it is recommended that the daemon be disabled." 272 | impact 1.0 273 | 274 | tag cis: 'distribution-independent-linux:2.1.10' 275 | tag level: 1 276 | 277 | describe service('xinetd') do 278 | it { should_not be_enabled } 279 | it { should_not be_running } 280 | end 281 | end 282 | -------------------------------------------------------------------------------- /controls/2_2_special_purpose_services.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '2.2 Special Purpose Services' 21 | 22 | control 'cis-dil-benchmark-2.2.1.1' do 23 | title 'Ensure time synchronization is in use' 24 | desc "System time should be synchronized between all systems in an environment. This is typically done by establishing an authoritative time server or set of servers and having all systems synchronize their clocks to them.\n\nRationale: Time synchronization is important to support time sensitive security mechanisms like Kerberos and also ensures log files have consistent time records across the enterprise, which aids in forensic investigations." 25 | impact 0.0 26 | 27 | tag cis: 'distribution-independent-linux:2.2.1.1' 28 | tag level: 1 29 | 30 | describe.one do 31 | describe package('ntp') do 32 | it { should be_installed } 33 | end 34 | 35 | describe command('ntpd') do 36 | it { should exist } 37 | end 38 | 39 | describe package('chrony') do 40 | it { should be_installed } 41 | end 42 | 43 | describe command('chronyd') do 44 | it { should exist } 45 | end 46 | end 47 | end 48 | 49 | control 'cis-dil-benchmark-2.2.1.2' do 50 | title 'Ensure ntp is configured' 51 | desc "ntp is a daemon which implements the Network Time Protocol (NTP). It is designed to synchronize system clocks across a variety of systems and use a source that is highly accurate. More information on NTP can be found at http://www.ntp.org. ntp can be configured to be a client and/or a server.\nThis recommendation only applies if ntp is in use on the system.\n\nRationale: If ntp is in use on the system proper configuration is vital to ensuring time synchronization is working properly." 52 | impact 1.0 53 | 54 | tag cis: 'distribution-independent-linux:2.2.1.2' 55 | tag level: 1 56 | 57 | only_if do 58 | package('ntp').installed? || command('ntpd').exist? 59 | end 60 | 61 | describe.one do 62 | describe ntp_conf do 63 | its(:server) { should_not eq nil } 64 | end 65 | 66 | describe ntp_conf do 67 | its(:pool) { should_not eq nil } 68 | end 69 | end 70 | 71 | describe ntp_conf.restrict.to_s do 72 | it { should match(/default\s+(\S+\s+)*kod(?:\s+|\s?")/) } 73 | it { should match(/default\s+(\S+\s+)*nomodify(?:\s+|\s?")/) } 74 | it { should match(/default\s+(\S+\s+)*notrap(?:\s+|\s?")/) } 75 | it { should match(/default\s+(\S+\s+)*nopeer(?:\s+|\s?")/) } 76 | it { should match(/default\s+(\S+\s+)*noquery(?:\s+|\s?")/) } 77 | end 78 | 79 | describe.one do 80 | describe file('/etc/init.d/ntp') do 81 | its(:content) { should match(/^RUNASUSER=ntp\s*(?:#.*)?$/) } 82 | end 83 | 84 | describe file('/etc/init.d/ntpd') do 85 | its(:content) { should match(/daemon\s+(\S+\s+)-u ntp:ntp(?:\s+|\s?")/) } 86 | end 87 | 88 | describe file('/etc/sysconfig/ntpd') do 89 | its(:content) { should match(/^OPTIONS="(?:.)?-u ntp:ntp\s*(?:.)?"\s*(?:#.*)?$/) } 90 | end 91 | 92 | describe file('/usr/lib/systemd/system/ntpd.service') do 93 | its(:content) { should match(%r{^ExecStart=/usr/s?bin/ntpd (?:.)?-u ntp:ntp\s*(?:.)?$}) } 94 | end 95 | end 96 | end 97 | 98 | control 'cis-dil-benchmark-2.2.1.3' do 99 | title 'Ensure chrony is configured' 100 | desc "chrony is a daemon which implements the Network Time Protocol (NTP) is designed to synchronize system clocks across a variety of systems and use a source that is highly accurate. More information on chrony can be found at http://chrony.tuxfamily.org/. chrony can be configured to be a client and/or a server.\n\nRationale: If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly.\nThis recommendation only applies if chrony is in use on the system." 101 | impact 1.0 102 | 103 | tag cis: 'distribution-independent-linux:2.2.1.3' 104 | tag level: 1 105 | 106 | only_if do 107 | package('chrony').installed? || command('chronyd').exist? 108 | end 109 | 110 | # Amazon Linux sources configuration from /run/chrony.d and /etc/chrony.d 111 | chrony_conf_files = ['/etc/chrony/chrony.conf', '/etc/chrony.conf'] 112 | chrony_conf_files += command('find /run/chrony.d -name \'*.sources\'').stdout.split 113 | chrony_conf_files += command('find /etc/chrony.d -name \'*.sources\'').stdout.split 114 | 115 | describe.one do 116 | chrony_conf_files.each do |f| 117 | describe file(f) do 118 | its('content') { should match(/^(pool|server)\s+\S+/) } 119 | end 120 | end 121 | end 122 | 123 | describe processes('chronyd') do 124 | its(:users) { should be_in %w(chrony _chrony) } 125 | end 126 | end 127 | 128 | control 'cis-dil-benchmark-2.2.1.4' do 129 | title 'Ensure systemd-timesyncd is configured' 130 | desc "systemd-timesyncd is a daemon that has been added for synchronizing the system clock across the network. It implements an SNTP client. In contrast to NTP implementations such as chrony or the NTP reference server this only implements a client side, and does not bother with the full NTP complexity, focusing only on querying time from one remote server and synchronizing the local clock to it. The daemon runs with minimal privileges, and has been hooked up with networkd to only operate when network connectivity is available. The daemon saves the current clock to disk every time a new NTP sync has been acquired, and uses this to possibly correct the system clock early at bootup, in order to accommodate for systems that lack an RTC such as the Raspberry Pi and embedded devices, and make sure that time monotonically progresses on these systems, even if it is not always correct. To make use of this daemon a new system user and group 'systemd- timesync' needs to be created on installation of systemd. This recommendation only applies if timesyncd is in use on the system." 131 | impact 1.0 132 | 133 | tag cis: 'distribution-independent-linux:2.2.1.4' 134 | tag level: 1 135 | 136 | only_if do 137 | service('systemd-timesyncd.service').enabled? 138 | end 139 | 140 | describe file('/etc/systemd/timesyncd.conf') do 141 | its('content') { should match /^NTP=\S+/ } 142 | its('content') { should match /^FallbackNTP=\S+/ } 143 | its('content') { should match /^RootDistanceMaxSec=[0-9]/ } 144 | end 145 | end 146 | 147 | control 'cis-dil-benchmark-2.2.2' do 148 | title 'Ensure X Window System is not installed' 149 | desc "The X Window System provides a Graphical User Interface (GUI) where users can have multiple windows in which to run programs and various add on. The X Windows system is typically used on workstations where users login, but not on servers where users typically do not login.\n\nRationale: Unless your organization specifically requires graphical login access via X Windows, remove it to reduce the potential attack surface." 150 | impact 1.0 151 | 152 | tag cis: 'distribution-independent-linux:2.2.2' 153 | tag level: 1 154 | 155 | describe packages(/^xserver-xorg.*/) do 156 | its(:names) { should be_empty } 157 | end 158 | 159 | describe packages(/^xorg-x11-server.*/) do 160 | its(:names) { should be_empty } 161 | end 162 | end 163 | 164 | control 'cis-dil-benchmark-2.2.3' do 165 | title 'Ensure Avahi Server is not enabled' 166 | desc "Avahi is a free zeroconf implementation, including a system for multicast DNS/DNS-SD service discovery. Avahi allows programs to publish and discover services and hosts running on a local network with no specific configuration. For example, a user can plug a computer into a network and Avahi automatically finds printers to print to, files to look at and people to talk to, as well as network services running on the machine.\n\nRationale: Automatic discovery of network services is not normally required for system functionality. It is recommended to disable the service to reduce the potential attach surface." 167 | impact 1.0 168 | 169 | tag cis: 'distribution-independent-linux:2.2.3' 170 | tag level: 1 171 | 172 | describe service('avahi-daemon') do 173 | it { should_not be_enabled } 174 | it { should_not be_running } 175 | end 176 | end 177 | 178 | control 'cis-dil-benchmark-2.2.4' do 179 | title 'Ensure CUPS is not enabled' 180 | desc "The Common Unix Print System (CUPS) provides the ability to print to both local and network printers. A system running CUPS can also accept print jobs from remote systems and print them to local printers. It also provides a web based remote administration capability.\n\nRationale: If the system does not need to print jobs or accept print jobs from other systems, it is recommended that CUPS be disabled to reduce the potential attack surface." 181 | impact 1.0 182 | 183 | tag cis: 'distribution-independent-linux:2.2.4' 184 | tag level: 1 185 | 186 | describe service('cups') do 187 | it { should_not be_enabled } 188 | it { should_not be_running } 189 | end 190 | end 191 | 192 | control 'cis-dil-benchmark-2.2.5' do 193 | title 'Ensure DHCP Server is not enabled' 194 | desc "The Dynamic Host Configuration Protocol (DHCP) is a service that allows machines to be dynamically assigned IP addresses.\n\nRationale: Unless a system is specifically set up to act as a DHCP server, it is recommended that this service be deleted to reduce the potential attack surface." 195 | impact 1.0 196 | 197 | tag cis: 'distribution-independent-linux:2.2.5' 198 | tag level: 1 199 | 200 | %w(isc-dhcp-server isc-dhcp-server6 dhcpd).each do |s| 201 | describe service(s) do 202 | it { should_not be_enabled } 203 | it { should_not be_running } 204 | end 205 | end 206 | end 207 | 208 | control 'cis-dil-benchmark-2.2.6' do 209 | title 'Ensure LDAP server is not enabled' 210 | desc "The Lightweight Directory Access Protocol (LDAP) was introduced as a replacement for NIS/YP. It is a service that provides a method for looking up information from a central database.\n\nRationale: If the system will not need to act as an LDAP server, it is recommended that the software be disabled to reduce the potential attack surface." 211 | impact 1.0 212 | 213 | tag cis: 'distribution-independent-linux:2.2.6' 214 | tag level: 1 215 | 216 | describe service('slapd') do 217 | it { should_not be_enabled } 218 | it { should_not be_running } 219 | end 220 | end 221 | 222 | control 'cis-dil-benchmark-2.2.7' do 223 | title 'Ensure NFS and RPC are not enabled' 224 | desc "The Network File System (NFS) is one of the first and most widely distributed file systems in the UNIX environment. It provides the ability for systems to mount file systems of other servers through the network.\n\nRationale: If the system does not export NFS shares or act as an NFS client, it is recommended that these services be disabled to reduce remote attack surface." 225 | impact 1.0 226 | 227 | tag cis: 'distribution-independent-linux:2.2.7' 228 | tag level: 1 229 | 230 | %w(nfs-kernel-server nfs rpcbind).each do |s| 231 | describe service(s) do 232 | it { should_not be_enabled } 233 | it { should_not be_running } 234 | end 235 | end 236 | end 237 | 238 | control 'cis-dil-benchmark-2.2.8' do 239 | title 'Ensure DNS Server is not enabled' 240 | desc "The Domain Name System (DNS) is a hierarchical naming system that maps names to IP addresses for computers, services and other resources connected to a network.\n\nRationale: Unless a system is specifically designated to act as a DNS server, it is recommended that the package be deleted to reduce the potential attack surface." 241 | impact 1.0 242 | 243 | tag cis: 'distribution-independent-linux:2.2.8' 244 | tag level: 1 245 | 246 | %w(named bind bind9).each do |s| 247 | describe service(s) do 248 | it { should_not be_enabled } 249 | it { should_not be_running } 250 | end 251 | end 252 | end 253 | 254 | control 'cis-dil-benchmark-2.2.9' do 255 | title 'Ensure FTP Server is not enabled' 256 | desc "The File Transfer Protocol (FTP) provides networked computers with the ability to transfer files.\n\nRationale: FTP does not protect the confidentiality of data or authentication credentials. It is recommended sftp be used if file transfer is required. Unless there is a need to run the system as a FTP server (for example, to allow anonymous downloads), it is recommended that the package be deleted to reduce the potential attack surface." 257 | impact 1.0 258 | 259 | tag cis: 'distribution-independent-linux:2.2.9' 260 | tag level: 1 261 | 262 | describe service('vsftpd') do 263 | it { should_not be_enabled } 264 | it { should_not be_running } 265 | end 266 | end 267 | 268 | control 'cis-dil-benchmark-2.2.10' do 269 | title 'Ensure HTTP server is not enabled' 270 | desc "HTTP or web servers provide the ability to host web site content.\n\nRationale: Unless there is a need to run the system as a web server, it is recommended that the package be deleted to reduce the potential attack surface." 271 | impact 1.0 272 | 273 | tag cis: 'distribution-independent-linux:2.2.10' 274 | tag level: 1 275 | 276 | %w(apache apache2 httpd lighttpd nginx).each do |s| 277 | describe service(s) do 278 | it { should_not be_enabled } 279 | it { should_not be_running } 280 | end 281 | end 282 | end 283 | 284 | control 'cis-dil-benchmark-2.2.11' do 285 | title 'Ensure IMAP and POP3 server is not enabled' 286 | desc "dovecot is an open source IMAP and POP3 server for Linux based systems.\n\nRationale: Unless POP3 and/or IMAP servers are to be provided by this system, it is recommended that the service be deleted to reduce the potential attack surface." 287 | impact 1.0 288 | 289 | tag cis: 'distribution-independent-linux:2.2.11' 290 | tag level: 1 291 | 292 | %w(dovecot courier-imap cyrus-imap).each do |s| 293 | describe service(s) do 294 | it { should_not be_enabled } 295 | it { should_not be_running } 296 | end 297 | end 298 | end 299 | 300 | control 'cis-dil-benchmark-2.2.12' do 301 | title 'Ensure Samba is not enabled' 302 | desc "The Samba daemon allows system administrators to configure their Linux systems to share file systems and directories with Windows desktops. Samba will advertise the file systems and directories via the Small Message Block (SMB) protocol. Windows desktop users will be able to mount these directories and file systems as letter drives on their systems.\n\nRationale: If there is no need to mount directories and file systems to Windows systems, then this service can be deleted to reduce the potential attack surface." 303 | impact 1.0 304 | 305 | tag cis: 'distribution-independent-linux:2.2.12' 306 | tag level: 1 307 | 308 | %w(samba smb smbd).each do |s| 309 | describe service(s) do 310 | it { should_not be_enabled } 311 | it { should_not be_running } 312 | end 313 | end 314 | end 315 | 316 | control 'cis-dil-benchmark-2.2.13' do 317 | title 'Ensure HTTP Proxy Server is not enabled' 318 | desc "Squid is a standard proxy server used in many distributions and environments.\n\nRationale: If there is no need for a proxy server, it is recommended that the squid proxy be deleted to reduce the potential attack surface." 319 | impact 1.0 320 | 321 | tag cis: 'distribution-independent-linux:2.2.13' 322 | tag level: 1 323 | 324 | %w(squid squid3).each do |s| 325 | describe service(s) do 326 | it { should_not be_enabled } 327 | it { should_not be_running } 328 | end 329 | end 330 | end 331 | 332 | control 'cis-dil-benchmark-2.2.14' do 333 | title 'Ensure SNMP Server is not enabled' 334 | desc "The Simple Network Management Protocol (SNMP) server is used to listen for SNMP commands from an SNMP management system, execute the commands or collect the information and then send results back to the requesting system.\n\nRationale: The SNMP server communicates using SNMP v1, which transmits data in the clear and does not require authentication to execute commands. Unless absolutely necessary, it is recommended that the SNMP service not be used." 335 | impact 1.0 336 | 337 | tag cis: 'distribution-independent-linux:2.2.14' 338 | tag level: 1 339 | 340 | describe service('snmpd') do 341 | it { should_not be_enabled } 342 | it { should_not be_running } 343 | end 344 | end 345 | 346 | control 'cis-dil-benchmark-2.2.15' do 347 | title 'Ensure mail transfer agent is configured for local-only mode' 348 | desc "Mail Transfer Agents (MTA), such as sendmail and Postfix, are used to listen for incoming mail and transfer the messages to the appropriate user or mail server. If the system is not intended to be a mail server, it is recommended that the MTA be configured to only process local mail.\n\nRationale: The software for all Mail Transfer Agents is complex and most have a long history of security issues. While it is important to ensure that the system can process local mail messages, it is not necessary to have the MTA's daemon listening on a port unless the server is intended to be a mail server that receives and processes mail from other systems." 349 | impact 1.0 350 | 351 | tag cis: 'distribution-independent-linux:2.2.15' 352 | tag level: 1 353 | 354 | describe port(25).where { address !~ /^(127\.0\.0\.1|::1)$/ } do 355 | its(:entries) { should be_empty } 356 | end 357 | end 358 | 359 | control 'cis-dil-benchmark-2.2.16' do 360 | title 'Ensure rsync service is not enabled' 361 | desc "The rsyncd service can be used to synchronize files between systems over network links.\n\nRationale: The rsyncd service presents a security risk as it uses unencrypted protocols for communication." 362 | impact 1.0 363 | 364 | tag cis: 'distribution-independent-linux:2.2.16' 365 | tag level: 1 366 | 367 | %w(rsync rsyncd).each do |s| 368 | describe service(s) do 369 | it { should_not be_enabled } 370 | it { should_not be_running } 371 | end 372 | end 373 | end 374 | 375 | control 'cis-dil-benchmark-2.2.17' do 376 | title 'Ensure NIS Server is not enabled' 377 | desc "The Network Information Service (NIS) (formally known as Yellow Pages) is a client-server directory service protocol for distributing system configuration files. The NIS server is a collection of programs that allow for the distribution of configuration files.\n\nRationale: The NIS service is inherently an insecure system that has been vulnerable to DOS attacks, buffer overflows and has poor authentication for querying NIS maps. NIS generally been replaced by such protocols as Lightweight Directory Access Protocol (LDAP). It is recommended that the service be disabled and other, more secure services be used" 378 | impact 1.0 379 | 380 | tag cis: 'distribution-independent-linux:2.2.17' 381 | tag level: 1 382 | 383 | %w(nis ypserv).each do |s| 384 | describe service(s) do 385 | it { should_not be_enabled } 386 | it { should_not be_running } 387 | end 388 | end 389 | end 390 | -------------------------------------------------------------------------------- /controls/2_3_service_clients.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '2.3 Service Clients' 21 | 22 | control 'cis-dil-benchmark-2.3.1' do 23 | title 'Ensure NIS Client is not installed' 24 | desc "The Network Information Service (NIS), formerly known as Yellow Pages, is a client-server directory service protocol used to distribute system configuration files. The NIS client (ypbind) was used to bind a machine to an NIS server and receive the distributed configuration files.\n\nRationale: The NIS service is inherently an insecure system that has been vulnerable to DOS attacks, buffer overflows and has poor authentication for querying NIS maps. NIS generally has been replaced by such protocols as Lightweight Directory Access Protocol (LDAP). It is recommended that the service be removed." 25 | impact 1.0 26 | 27 | tag cis: 'distribution-independent-linux:2.3.1' 28 | tag level: 1 29 | 30 | %w(nis ypbind).each do |p| 31 | describe package(p) do 32 | it { should_not be_installed } 33 | end 34 | end 35 | end 36 | 37 | control 'cis-dil-benchmark-2.3.2' do 38 | title 'Ensure rsh client is not installed' 39 | desc "The rsh package contains the client commands for the rsh services.\n\nRationale: These legacy clients contain numerous security exposures and have been replaced with the more secure SSH package. Even if the server is removed, it is best to ensure the clients are also removed to prevent users from inadvertently attempting to use these commands and therefore exposing their credentials. Note that removing the rsh package removes the clients for rsh, rcp and rlogin." 40 | impact 1.0 41 | 42 | tag cis: 'distribution-independent-linux:2.3.2' 43 | tag level: 1 44 | 45 | %w(rsh-client rsh-redone-client rsh).each do |p| 46 | describe package(p) do 47 | it { should_not be_installed } 48 | end 49 | end 50 | end 51 | 52 | control 'cis-dil-benchmark-2.3.3' do 53 | title 'Ensure talk client is not installed' 54 | desc "The talk software makes it possible for users to send and receive messages across systems through a terminal session. The talk client, which allows initialization of talk sessions, is installed by default.\n\nRationale: The software presents a security risk as it uses unencrypted protocols for communication." 55 | impact 1.0 56 | 57 | tag cis: 'distribution-independent-linux:2.3.3' 58 | tag level: 1 59 | 60 | describe package('talk') do 61 | it { should_not be_installed } 62 | end 63 | end 64 | 65 | control 'cis-dil-benchmark-2.3.4' do 66 | title 'Ensure telnet client is not installed' 67 | desc "The telnet package contains the telnet client, which allows users to start connections to other systems via the telnet protocol.\n\nRationale: The telnet protocol is insecure and unencrypted. The use of an unencrypted transmission medium could allow an unauthorized user to steal credentials. The ssh package provides an encrypted session and stronger security and is included in most Linux distributions." 68 | impact 1.0 69 | 70 | tag cis: 'distribution-independent-linux:2.3.4' 71 | tag level: 1 72 | 73 | describe package('telnet') do 74 | it { should_not be_installed } 75 | end 76 | end 77 | 78 | control 'cis-dil-benchmark-2.3.5' do 79 | title 'Ensure LDAP client is not installed' 80 | desc "The Lightweight Directory Access Protocol (LDAP) was introduced as a replacement for NIS/YP. It is a service that provides a method for looking up information from a central database.\n\nRationale: If the system will not need to act as an LDAP client, it is recommended that the software be removed to reduce the potential attack surface." 81 | impact 1.0 82 | 83 | tag cis: 'distribution-independent-linux:2.3.5' 84 | tag level: 1 85 | 86 | %w(ldap-utils openldap-clients openldap2-client).each do |p| 87 | describe package(p) do 88 | it { should_not be_installed } 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /controls/3_1_network_parameters_host_only.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '3.1 Network Parameters (Host Only)' 21 | 22 | ipv6 = command('test -f /proc/net/if_inet6').exit_status 23 | 24 | control 'cis-dil-benchmark-3.1.1' do 25 | title 'Ensure IP forwarding is disabled' 26 | desc "The net.ipv4.ip_forward flag is used to tell the system whether it can forward packets or not.\n\nRationale: Setting the flag to 0 ensures that a system with multiple interfaces (for example, a hard proxy), will never be able to forward packets, and therefore, never serve as a router." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:3.1.1' 30 | tag level: 1 31 | 32 | parameters = ['net.ipv4.ip_forward'] 33 | if ipv6.zero? 34 | parameters += ['net.ipv6.conf.all.forwarding'] 35 | end 36 | 37 | parameters.each do |kp| 38 | describe kernel_parameter(kp) do 39 | its('value') { should_not be_nil } 40 | its('value') { should cmp 0 } 41 | end 42 | end 43 | end 44 | 45 | control 'cis-dil-benchmark-3.1.2' do 46 | title 'Ensure packet redirect sending is disabled' 47 | desc "ICMP Redirects are used to send routing information to other hosts. As a host itself does not act as a router (in a host only configuration), there is no need to send redirects.\n\nRationale: An attacker could use a compromised host to send invalid ICMP redirects to other router devices in an attempt to corrupt routing and have users access a system set up by the attacker as opposed to a valid system." 48 | impact 1.0 49 | 50 | tag cis: 'distribution-independent-linux:3.1.2' 51 | tag level: 1 52 | 53 | %w( 54 | net.ipv4.conf.all.send_redirects 55 | net.ipv4.conf.default.send_redirects 56 | ).each do |kp| 57 | describe kernel_parameter(kp) do 58 | its('value') { should_not be_nil } 59 | its('value') { should cmp 0 } 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /controls/3_2_network_parameters_host_and_router.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '3.2 Network Parameters (Host and Router)' 21 | 22 | ipv6 = command('test -f /proc/net/if_inet6').exit_status 23 | 24 | control 'cis-dil-benchmark-3.2.1' do 25 | title 'Ensure source routed packets are not accepted' 26 | desc "In networking, source routing allows a sender to partially or fully specify the route packets take through a network. In contrast, non-source routed packets travel a path determined by routers in the network. In some cases, systems may not be routable or reachable from some locations (e.g. private addresses vs. Internet routable), and so source routed packets would need to be used.\n\nRationale: Setting net.ipv4.conf.all.accept_source_route and net.ipv4.conf.default.accept_source_route to 0 disables the system from accepting source routed packets. Assume this system was capable of routing packets to Internet routable addresses on one interface and private addresses on another interface. Assume that the private addresses were not routable to the Internet routable addresses and vice versa. Under normal routing circumstances, an attacker from the Internet routable addresses could not use the system as a way to reach the private address systems. If, however, source routed packets were allowed, they could be used to gain access to the private address systems as the route could be specified, rather than rely on routing protocols that did not allow this routing." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:3.2.1' 30 | tag level: 1 31 | 32 | parameters = [ 33 | 'net.ipv4.conf.all.accept_source_route', 34 | 'net.ipv4.conf.default.accept_source_route', 35 | ] 36 | if ipv6.zero? 37 | parameters += [ 38 | 'net.ipv6.conf.all.accept_source_route', 39 | 'net.ipv6.conf.default.accept_source_route', 40 | ] 41 | end 42 | 43 | parameters.each do |kp| 44 | describe kernel_parameter(kp) do 45 | its(:value) { should_not be_nil } 46 | its(:value) { should eq 0 } 47 | end 48 | end 49 | end 50 | 51 | control 'cis-dil-benchmark-3.2.2' do 52 | title 'Ensure ICMP redirects are not accepted' 53 | desc "ICMP redirect messages are packets that convey routing information and tell your host (acting as a router) to send packets via an alternate path. It is a way of allowing an outside routing device to update your system routing tables. By setting net.ipv4.conf.all.accept_redirects to 0, the system will not accept any ICMP redirect messages, and therefore, won't allow outsiders to update the system's routing tables.\n\nRationale: Attackers could use bogus ICMP redirect messages to maliciously alter the system routing tables and get them to send packets to incorrect networks and allow your system packets to be captured." 54 | impact 1.0 55 | 56 | tag cis: 'distribution-independent-linux:3.2.2' 57 | tag level: 1 58 | 59 | parameters = [ 60 | 'net.ipv4.conf.all.accept_redirects', 61 | 'net.ipv4.conf.default.accept_redirects', 62 | ] 63 | if ipv6.zero? 64 | parameters += [ 65 | 'net.ipv6.conf.all.accept_redirects', 66 | 'net.ipv6.conf.default.accept_redirects', 67 | ] 68 | end 69 | 70 | parameters.each do |kp| 71 | describe kernel_parameter(kp) do 72 | its(:value) { should_not be_nil } 73 | its(:value) { should eq 0 } 74 | end 75 | end 76 | end 77 | 78 | control 'cis-dil-benchmark-3.2.3' do 79 | title 'Ensure secure ICMP redirects are not accepted' 80 | desc "Secure ICMP redirects are the same as ICMP redirects, except they come from gateways listed on the default gateway list. It is assumed that these gateways are known to your system, and that they are likely to be secure.\n\nRationale: It is still possible for even known gateways to be compromised. Setting net.ipv4.conf.all.secure_redirects to 0 protects the system from routing table updates by possibly compromised known gateways." 81 | impact 1.0 82 | 83 | tag cis: 'distribution-independent-linux:3.2.3' 84 | tag level: 1 85 | 86 | %w(net.ipv4.conf.all.secure_redirects net.ipv4.conf.default.secure_redirects).each do |kp| 87 | describe kernel_parameter(kp) do 88 | its(:value) { should_not be_nil } 89 | its(:value) { should eq 0 } 90 | end 91 | end 92 | end 93 | 94 | control 'cis-dil-benchmark-3.2.4' do 95 | title 'Ensure suspicious packets are logged' 96 | desc "When enabled, this feature logs packets with un-routable source addresses to the kernel log.\n\nRationale: Enabling this feature and logging these packets allows an administrator to investigate the possibility that an attacker is sending spoofed packets to their system." 97 | impact 1.0 98 | 99 | tag cis: 'distribution-independent-linux:3.2.4' 100 | tag level: 1 101 | 102 | %w(net.ipv4.conf.all.log_martians net.ipv4.conf.default.log_martians).each do |kp| 103 | describe kernel_parameter(kp) do 104 | its(:value) { should_not be_nil } 105 | its(:value) { should eq 1 } 106 | end 107 | end 108 | end 109 | 110 | control 'cis-dil-benchmark-3.2.5' do 111 | title 'Ensure broadcast ICMP requests are ignored' 112 | desc "Setting net.ipv4.icmp_echo_ignore_broadcasts to 1 will cause the system to ignore all ICMP echo and timestamp requests to broadcast and multicast addresses.\n\nRationale: Accepting ICMP echo and timestamp requests with broadcast or multicast destinations for your network could be used to trick your host into starting (or participating) in a Smurf attack. A Smurf attack relies on an attacker sending large amounts of ICMP broadcast messages with a spoofed source address. All hosts receiving this message and responding would send echo-reply messages back to the spoofed address, which is probably not routable. If many hosts respond to the packets, the amount of traffic on the network could be significantly multiplied." 113 | impact 1.0 114 | 115 | tag cis: 'distribution-independent-linux:3.2.5' 116 | tag level: 1 117 | 118 | describe kernel_parameter('net.ipv4.icmp_echo_ignore_broadcasts') do 119 | its(:value) { should_not be_nil } 120 | its(:value) { should eq 1 } 121 | end 122 | end 123 | 124 | control 'cis-dil-benchmark-3.2.6' do 125 | title 'Ensure bogus ICMP responses are ignored' 126 | desc "Setting icmp_ignore_bogus_error_responses to 1 prevents the kernel from logging bogus responses (RFC-1122 non-compliant) from broadcast reframes, keeping file systems from filling up with useless log messages.\n\nRationale: Some routers (and some attackers) will send responses that violate RFC-1122 and attempt to fill up a log file system with many useless error messages." 127 | impact 1.0 128 | 129 | tag cis: 'distribution-independent-linux:3.2.6' 130 | tag level: 1 131 | 132 | describe kernel_parameter('net.ipv4.icmp_ignore_bogus_error_responses') do 133 | its(:value) { should_not be_nil } 134 | its(:value) { should eq 1 } 135 | end 136 | end 137 | 138 | control 'cis-dil-benchmark-3.2.7' do 139 | title 'Ensure Reverse Path Filtering is enabled' 140 | desc "Setting net.ipv4.conf.all.rp_filter and net.ipv4.conf.default.rp_filter to 1 forces the Linux kernel to utilize reverse path filtering on a received packet to determine if the packet was valid. Essentially, with reverse path filtering, if the return packet does not go out the same interface that the corresponding source packet came from, the packet is dropped (and logged if log_martians is set).\n\nRationale: Setting these flags is a good way to deter attackers from sending your system bogus packets that cannot be responded to. One instance where this feature breaks down is if asymmetrical routing is employed. This would occur when using dynamic routing protocols (bgp, ospf, etc) on your system. If you are using asymmetrical routing on your system, you will not be able to enable this feature without breaking the routing." 141 | impact 1.0 142 | 143 | tag cis: 'distribution-independent-linux:3.2.7' 144 | tag level: 1 145 | 146 | %w(net.ipv4.conf.all.rp_filter net.ipv4.conf.default.rp_filter).each do |kp| 147 | describe kernel_parameter(kp) do 148 | its(:value) { should_not be_nil } 149 | its(:value) { should eq 1 } 150 | end 151 | end 152 | end 153 | 154 | control 'cis-dil-benchmark-3.2.8' do 155 | title 'Ensure TCP SYN Cookies is enabled' 156 | desc "When tcp_syncookies is set, the kernel will handle TCP SYN packets normally until the half-open connection queue is full, at which time, the SYN cookie functionality kicks in. SYN cookies work by not using the SYN queue at all. Instead, the kernel simply replies to the SYN with a SYN|ACK, but will include a specially crafted TCP sequence number that encodes the source and destination IP address and port number and the time the packet was sent. A legitimate connection would send the ACK packet of the three way handshake with the specially crafted sequence number. This allows the system to verify that it has received a valid response to a SYN cookie and allow the connection, even though there is no corresponding SYN in the queue.\n\nRationale: Attackers use SYN flood attacks to perform a denial of service attacked on a system by sending many SYN packets without completing the three way handshake. This will quickly use up slots in the kernel's half-open connection queue and prevent legitimate connections from succeeding. SYN cookies allow the system to keep accepting valid connections, even if under a denial of service attack." 157 | impact 1.0 158 | 159 | tag cis: 'distribution-independent-linux:3.2.8' 160 | tag level: 1 161 | 162 | describe kernel_parameter('net.ipv4.tcp_syncookies') do 163 | its(:value) { should_not be_nil } 164 | its(:value) { should eq 1 } 165 | end 166 | end 167 | 168 | control 'cis-dil-benchmark-3.2.9' do 169 | title 'Ensure IPv6 router advertisements are not accepted' 170 | desc "This setting disables the system's ability to accept IPv6 router advertisements.\n\nRationale: It is recommended that systems do not accept router advertisements as they could be tricked into routing traffic to compromised machines. Setting hard routes within the system (usually a single default route to a trusted router) protects the system from bad routes." 171 | impact 1.0 172 | 173 | tag cis: 'distribution-independent-linux:3.2.9' 174 | tag level: 1 175 | 176 | %w(net.ipv6.conf.all.accept_ra net.ipv6.conf.default.accept_ra).each do |kp| 177 | describe kernel_parameter(kp) do 178 | its(:value) { should_not be_nil } 179 | its(:value) { should eq 0 } 180 | end 181 | end 182 | 183 | only_if { ipv6.zero? } 184 | end 185 | -------------------------------------------------------------------------------- /controls/3_3_tcp_wrappers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '3.3 TCP Wrappers' 21 | 22 | control 'cis-dil-benchmark-3.3.1' do 23 | title 'Ensure TCP Wrappers is installed' 24 | desc ' 25 | Many Linux distributions provide value-added firewall solutions which provide easy, advanced management of network traffic into and out 26 | of the local system. When these solutions are available and appropriate for an environment they should be used. 27 | 28 | In cases where a value-added firewall is not provided by a distribution, TCP Wrappers provides a simple access 29 | list and standardized logging method for services capable of supporting it. Services that are called from `inetd` and `xinetd` support the use 30 | of TCP wrappers. Any service that can support TCP wrappers will have the `libwrap.so` library attached to it. 31 | ' 32 | impact 0.0 33 | 34 | tag cis: 'distribution-independent-linux:3.3.1' 35 | tag level: 1 36 | 37 | describe.one do 38 | %w(tcpd tcp_wrappers).each do |p| 39 | describe package(p) do 40 | it { should be_installed } 41 | end 42 | end 43 | end 44 | end 45 | 46 | control 'cis-dil-benchmark-3.3.2' do 47 | title 'Ensure /etc/hosts.allow is configured' 48 | desc ' 49 | The `/etc/hosts.allow` file specifies which IP addresses are permitted to connect 50 | to the host. It is intended to be used in conjunction with the `/etc/hosts.deny` file. 51 | ' 52 | impact 0.0 53 | 54 | tag cis: 'distribution-independent-linux:3.3.2' 55 | tag level: 1 56 | 57 | describe file('/etc/hosts.allow') do 58 | it { should exist } 59 | end 60 | end 61 | 62 | control 'cis-dil-benchmark-3.3.3' do 63 | title 'Ensure /etc/hosts.deny is configured' 64 | desc ' 65 | The /etc/hosts.deny file specifies which IP addresses are not permitted to connect to the host. 66 | It is intended to be used in conjunction with the /etc/hosts.allow file. 67 | 68 | Rationale: The /etc/hosts.deny file serves as a failsafe so that any host not specified 69 | in /etc/hosts.allow is denied access to the system. 70 | ' 71 | impact 0.0 72 | 73 | tag cis: 'distribution-independent-linux:3.3.3' 74 | tag level: 1 75 | 76 | describe file('/etc/hosts.deny') do 77 | its('content') { should match(/^ALL: ALL/) } 78 | end 79 | end 80 | 81 | control 'cis-dil-benchmark-3.3.4' do 82 | title 'Ensure permissions on /etc/hosts.allow are configured' 83 | desc ' 84 | The /etc/hosts.allow file contains networking information that is used by many applications and 85 | therefore must be readable for these applications to operate. 86 | 87 | Rationale: It is critical to ensure that the /etc/hosts.allow file is protected from unauthorized write access. Although it is protected by default, 88 | the file permissions could be changed either inadvertently or through malicious actions. 89 | ' 90 | impact 1.0 91 | 92 | tag cis: 'distribution-independent-linux:3.3.4' 93 | tag level: 1 94 | 95 | describe file('/etc/hosts.allow') do 96 | it { should exist } 97 | it { should be_file } 98 | 99 | its('owner') { should cmp 'root' } 100 | its('group') { should cmp 'root' } 101 | 102 | its('mode') { should cmp '0644' } 103 | end 104 | end 105 | 106 | control 'cis-dil-benchmark-3.3.5' do 107 | title 'Ensure permissions on /etc/hosts.deny are configured' 108 | desc ' 109 | The `/etc/hosts.deny` file contains network information that is used by many system applications and therefore 110 | must be readable for these applications to operate. 111 | ' 112 | impact 1.0 113 | 114 | tag cis: 'distribution-independent-linux:3.3.5' 115 | tag level: 1 116 | 117 | describe file('/etc/hosts.deny') do 118 | it { should exist } 119 | it { should be_file } 120 | 121 | its('owner') { should cmp 'root' } 122 | its('group') { should cmp 'root' } 123 | 124 | its('mode') { should cmp '0644' } 125 | end 126 | end 127 | -------------------------------------------------------------------------------- /controls/3_4_uncommon_network_protocols.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | cis_level = input('cis_level') 21 | 22 | title '3.4 Uncommon Network Protocols' 23 | 24 | control 'cis-dil-benchmark-3.4.1' do 25 | title 'Ensure DCCP is disabled' 26 | desc "The Datagram Congestion Control Protocol (DCCP) is a transport layer protocol that supports streaming media and telephony. DCCP provides a way to gain access to congestion control, without having to do it at the application layer, but does not provide in-sequence delivery.\n\nRationale: If the protocol is not required, it is recommended that the drivers not be installed to reduce the potential attack surface." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:3.4.1' 30 | tag level: 2 31 | 32 | only_if { cis_level == 2 } 33 | 34 | describe kernel_module('dccp') do 35 | it { should_not be_loaded } 36 | it { should be_disabled } 37 | end 38 | end 39 | 40 | control 'cis-dil-benchmark-3.4.2' do 41 | title 'Ensure SCTP is disabled' 42 | desc "The Stream Control Transmission Protocol (SCTP) is a transport layer protocol used to support message oriented communication, with several streams of messages in one connection. It serves a similar function as TCP and UDP, incorporating features of both. It is message-oriented like UDP, and ensures reliable in-sequence transport of messages with congestion control like TCP.\n\nRationale: If the protocol is not being used, it is recommended that kernel module not be loaded, disabling the service to reduce the potential attack surface." 43 | impact 1.0 44 | 45 | tag cis: 'distribution-independent-linux:3.4.2' 46 | tag level: 2 47 | 48 | only_if { cis_level == 2 } 49 | 50 | describe kernel_module('sctp') do 51 | it { should_not be_loaded } 52 | it { should be_disabled } 53 | end 54 | end 55 | 56 | control 'cis-dil-benchmark-3.4.3' do 57 | title 'Ensure RDS is disabled' 58 | desc "The Reliable Datagram Sockets (RDS) protocol is a transport layer protocol designed to provide low-latency, high-bandwidth communications between cluster nodes. It was developed by the Oracle Corporation.\n\nRationale: If the protocol is not being used, it is recommended that kernel module not be loaded, disabling the service to reduce the potential attack surface." 59 | impact 1.0 60 | 61 | tag cis: 'distribution-independent-linux:3.4.3' 62 | tag level: 2 63 | 64 | only_if { cis_level == 2 } 65 | 66 | describe kernel_module('rds') do 67 | it { should_not be_loaded } 68 | it { should be_disabled } 69 | end 70 | end 71 | 72 | control 'cis-dil-benchmark-3.4.4' do 73 | title 'Ensure TIPC is disabled' 74 | desc "The Transparent Inter-Process Communication (TIPC) protocol is designed to provide communication between cluster nodes.\n\nRationale: If the protocol is not being used, it is recommended that kernel module not be loaded, disabling the service to reduce the potential attack surface." 75 | impact 1.0 76 | 77 | tag cis: 'distribution-independent-linux:3.4.4' 78 | tag level: 2 79 | 80 | only_if { cis_level == 2 } 81 | 82 | describe kernel_module('tipc') do 83 | it { should_not be_loaded } 84 | it { should be_disabled } 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /controls/3_5_firewall_configuration.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '3.5 Firewall Configuration' 21 | 22 | ipv6 = command('test -f /proc/net/if_inet6').exit_status 23 | 24 | control 'cis-dil-benchmark-3.5.1.1' do 25 | title 'Ensure IPv6 default deny firewall policy' 26 | desc "A default deny all policy on connections ensures that any unconfigured network usage will be rejected.\n\nRationale: With a default accept policy the firewall will accept any packet that is not configured to be denied. It is easier to white list acceptable usage than to black list unacceptable usage." 27 | impact 1.0 28 | 29 | tag cis: 'distribution-independent-linux:3.5.1.1' 30 | tag level: 1 31 | 32 | describe ip6tables do 33 | it { should have_rule('-P INPUT DROP') } 34 | it { should have_rule('-P OUTPUT DROP') } 35 | it { should have_rule('-P FORWARD DROP') } 36 | end 37 | 38 | only_if { ipv6.zero? } 39 | end 40 | 41 | control 'cis-dil-benchmark-3.5.1.2' do 42 | title 'Ensure IPv6 loopback traffic is configured' 43 | desc "Configure the loopback interface to accept traffic. Configure all other interfaces to deny traffic to the loopback network (::1).\n\nRationale: Loopback traffic is generated between processes on machine and is typically critical to operation of the system. The loopback interface is the only place that loopback network (::1) traffic should be seen, all other interfaces should ignore traffic on this network as an anti-spoofing measure." 44 | impact 1.0 45 | 46 | tag cis: 'distribution-independent-linux:3.5.1.2' 47 | tag level: 1 48 | 49 | # Using match instead of have_rule to ensure tests work with iptables rule that have comments 50 | # https://github.com/inspec/inspec/issues/3039 51 | 52 | rules = ip6tables.retrieve_rules 53 | 54 | describe.one do 55 | rules.each do |rule| 56 | describe rule do 57 | it { should match(/(?=.*-A INPUT)(?=.*-i lo)(?=.*-j ACCEPT)/) } 58 | end 59 | end 60 | end 61 | 62 | describe.one do 63 | rules.each do |rule| 64 | describe rule do 65 | it { should match(/(?=.*-A OUTPUT)(?=.*-o lo)(?=.*-j ACCEPT)/) } 66 | end 67 | end 68 | end 69 | 70 | describe.one do 71 | rules.each do |rule| 72 | describe rule do 73 | it { should match(/(?=.*-A INPUT)(?=.*-s ::1)(?=.*-j DROP)/) } 74 | end 75 | end 76 | end 77 | 78 | only_if { ipv6.zero? } 79 | end 80 | 81 | control 'cis-dil-benchmark-3.5.1.3' do 82 | title 'Ensure IPv6 outbound and established connections are configured' 83 | desc "Configure the firewall rules for new outbound, and established IPv6 connections.\n\nRationale: If rules are not in place for new outbound, and established connections all packets will be dropped by the default policy preventing network usage." 84 | impact 0.0 85 | 86 | tag cis: 'distribution-independent-linux:3.5.1.3' 87 | tag level: 1 88 | 89 | rules = ip6tables.retrieve_rules 90 | 91 | %w(tcp udp icmp).each do |proto| 92 | describe.one do 93 | rules.each do |rule| 94 | describe rule do 95 | it { should match(/(?=.*-A OUTPUT)(?=.*-p #{proto})(?=.*-m state --state NEW,ESTABLISHED)(?=.*-j ACCEPT)/) } 96 | end 97 | end 98 | end 99 | 100 | describe.one do 101 | rules.each do |rule| 102 | describe rule do 103 | it { should match(/(?=.*-A INPUT)(?=.*-p #{proto})(?=.*-m state --state ESTABLISHED)(?=.*-j ACCEPT)/) } 104 | end 105 | end 106 | end 107 | end 108 | 109 | only_if { ipv6.zero? } 110 | end 111 | 112 | control 'cis-dil-benchmark-3.5.1.4' do 113 | title 'Ensure IPv6 firewall rules exist for all open ports' 114 | desc "Any ports that have been opened on non-loopback addresses need firewall rules to govern traffic.\n\nRationale: Without a firewall rule configured for open ports default firewall policy will drop all packets to these ports." 115 | impact 0.0 116 | 117 | tag cis: 'distribution-independent-linux:3.5.1.4' 118 | tag level: 1 119 | 120 | port.where { address !~ /^(127\.[0-9]+\.[0-9]+\.[0-9]+|::1)$/ }.ports.each do |port| 121 | describe "Firewall rule should exist for port #{port}" do 122 | subject { ip6tables.retrieve_rules.any? { |s| s =~ /\s--(dport|dports) #{port}\s/ } } 123 | it { should be true } 124 | end 125 | end 126 | 127 | only_if { ipv6.zero? } 128 | end 129 | 130 | control 'cis-dil-benchmark-3.5.2.1' do 131 | title 'Ensure default deny firewall policy' 132 | desc "A default deny all policy on connections ensures that any unconfigured network usage will be rejected.\n\nRationale: With a default accept policy the firewall will accept any packet that is not configured to be denied. It is easier to white list acceptable usage than to black list unacceptable usage." 133 | impact 1.0 134 | 135 | tag cis: 'distribution-independent-linux:3.5.2.1' 136 | tag level: 1 137 | 138 | describe iptables do 139 | it { should have_rule('-P INPUT DROP') } 140 | it { should have_rule('-P OUTPUT DROP') } 141 | it { should have_rule('-P FORWARD DROP') } 142 | end 143 | end 144 | 145 | control 'cis-dil-benchmark-3.5.2.2' do 146 | title 'Ensure loopback traffic is configured' 147 | desc "Configure the loopback interface to accept traffic. Configure all other interfaces to deny traffic to the loopback network (127.0.0.0/8).\n\nRationale: Loopback traffic is generated between processes on machine and is typically critical to operation of the system. The loopback interface is the only place that loopback network (127.0.0.0/8) traffic should be seen, all other interfaces should ignore traffic on this network as an anti-spoofing measure." 148 | impact 1.0 149 | 150 | tag cis: 'distribution-independent-linux:3.5.2.2' 151 | tag level: 1 152 | 153 | rules = iptables.retrieve_rules 154 | 155 | describe.one do 156 | rules.each do |rule| 157 | describe rule do 158 | it { should match /(?=.*-A INPUT)(?=.*-i lo)(?=.*-j ACCEPT)/ } 159 | end 160 | end 161 | end 162 | 163 | describe.one do 164 | rules.each do |rule| 165 | describe rule do 166 | it { should match /(?=.*-A OUTPUT)(?=.*-o lo)(?=.*-j ACCEPT)/ } 167 | end 168 | end 169 | end 170 | 171 | describe.one do 172 | rules.each do |rule| 173 | describe rule do 174 | it { should match %r{(?=.*-A INPUT)(?=.*-s 127\.0\.0\.0/8)(?=.*-j DROP)} } 175 | end 176 | end 177 | end 178 | end 179 | 180 | control 'cis-dil-benchmark-3.5.2.3' do 181 | title 'Ensure outbound and established connections are configured' 182 | desc "Configure the firewall rules for new outbound, and established connections.\n\nRationale: If rules are not in place for new outbound, and established connections all packets will be dropped by the default policy preventing network usage." 183 | impact 0.0 184 | 185 | tag cis: 'distribution-independent-linux:3.5.2.3' 186 | tag level: 1 187 | 188 | rules = iptables.retrieve_rules 189 | 190 | %w(tcp udp icmp).each do |proto| 191 | describe.one do 192 | rules.each do |rule| 193 | describe rule do 194 | it { should match /(?=.*-A OUTPUT)(?=.*-p #{proto})(?=.*-m state --state NEW,ESTABLISHED)(?=.*-j ACCEPT)/ } 195 | end 196 | end 197 | end 198 | 199 | describe.one do 200 | rules.each do |rule| 201 | describe rule do 202 | it { should match /(?=.*-A INPUT)(?=.*-p #{proto})(?=.*-m state --state ESTABLISHED)(?=.*-j ACCEPT)/ } 203 | end 204 | end 205 | end 206 | end 207 | end 208 | 209 | control 'cis-dil-benchmark-3.5.2.4' do 210 | title 'Ensure firewall rules exist for all open ports' 211 | desc "Any ports that have been opened on non-loopback addresses need firewall rules to govern traffic.\n\nRationale: Without a firewall rule configured for open ports default firewall policy will drop all packets to these ports." 212 | impact 1.0 213 | 214 | tag cis: 'distribution-independent-linux:3.5.2.4' 215 | tag level: 1 216 | 217 | port.where { address !~ /^(127\.[0-9]+\.[0-9]+\.[0-9]+|::1)$/ }.ports.each do |port| 218 | describe "Firewall rule should exist for port #{port}" do 219 | subject { iptables.retrieve_rules.any? { |s| s =~ /\s--(dport|dports) #{port}\s/ } } 220 | it { should be true } 221 | end 222 | end 223 | end 224 | 225 | control 'cis-dil-benchmark-3.5.3' do 226 | title 'Ensure iptables is installed' 227 | desc "iptables allows configuration of the IPv4 tables in the linux kernel and the rules stored within them. Most firewall configuration utilities operate as a front end to iptables.\n\nRationale: iptables is required for firewall management and configuration." 228 | impact 1.0 229 | 230 | tag cis: 'distribution-independent-linux:3.5.3' 231 | tag level: 1 232 | 233 | describe.one do 234 | describe package('iptables') do 235 | it { should be_installed } 236 | end 237 | 238 | describe package('iptables-nft') do 239 | it { should be_installed } 240 | end 241 | end 242 | end 243 | -------------------------------------------------------------------------------- /controls/3_6_wireless_interfaces.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '3.6 Wireless interfaces' 21 | 22 | control 'cis-dil-benchmark-3.6' do 23 | title 'Ensure wireless interfaces are disabled' 24 | desc "Wireless networking is used when wired networks are unavailable. Debian contains a wireless tool kit to allow system administrators to configure and use wireless networks.\n\nRationale: If wireless is not to be used, wireless devices can be disabled to reduce the potential attack surface." 25 | impact 0.0 26 | 27 | tag cis: 'distribution-independent-linux:3.6' 28 | tag level: 1 29 | 30 | describe 'cis-dil-benchmark-3.6' do 31 | skip 'Not implemented' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /controls/3_7_disable_ipv6.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | cis_level = input('cis_level') 21 | 22 | title '3.7 Disable IPv6' 23 | 24 | control 'cis-dil-benchmark-3.7' do 25 | title 'Disable IPv6' 26 | desc "Although IPv6 has many advantages over IPv4, not all organizations have IPv6 or dual stack configurations implemented.\n\nRationale: If IPv6 or dual stack is not to be used, it is recommended that IPv6 be disabled to reduce the attack surface of the system." 27 | impact 0.0 28 | 29 | tag cis: 'distribution-independent-linux:3.7' 30 | tag level: 2 31 | 32 | only_if { cis_level == 2 } 33 | 34 | describe 'cis-dil-benchmark-3.7' do 35 | skip 'Not implemented' 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /controls/4_2_configure_logging.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '4.2 Configure Logging' 21 | 22 | control 'cis-dil-benchmark-4.2.1.1' do 23 | title 'Ensure rsyslog Service is insalled' 24 | desc ' 25 | The `rsyslog` software is a recommended replacement to the original `syslogd` daemon which provide 26 | improvements over `syslogd`, such as connection-oriented (i.e. TCP) transmission of logs, the option to log to database formats, 27 | and the encryption of log data en route to a central logging server. 28 | ' 29 | impact 1.0 30 | 31 | tag cis: 'distribution-independent-linux:4.2.1.1' 32 | tag level: 1 33 | 34 | describe package('rsyslog') do 35 | it { should be_installed } 36 | end 37 | end 38 | 39 | control 'cis-dil-benchmark-4.2.1.2' do 40 | title 'Ensure rsyslog Service is enabled' 41 | desc ' 42 | Once the rsyslog package is installed it needs to be activated. 43 | 44 | Rationale: If the rsyslog service is not activated the system may default to the syslogd service or lack logging instead. 45 | ' 46 | impact 1.0 47 | 48 | tag cis: 'distribution-independent-linux:4.2.1.2' 49 | tag level: 1 50 | 51 | describe service('rsyslog') do 52 | it { should be_enabled } 53 | it { should be_running } 54 | end 55 | end 56 | 57 | control 'cis-dil-benchmark-4.2.1.3' do 58 | title 'Ensure logging is configured' 59 | desc ' 60 | The /etc/rsyslog.conf file specifies rules for logging and which files are to be used to log certain classes of messages. 61 | 62 | Rationale: A great deal of important security-related information is sent via rsyslog (e.g., successful and failed su attempts, 63 | failed login attempts, root login attempts, etc.). 64 | ' 65 | impact 0.0 66 | 67 | tag cis: 'distribution-independent-linux:4.2.1.3' 68 | tag level: 1 69 | 70 | describe file('/etc/rsyslog.conf') do 71 | it { should exist } 72 | end 73 | end 74 | 75 | control 'cis-dil-benchmark-4.2.1.4' do 76 | title 'Ensure rsyslog default file permissions configured' 77 | desc ' 78 | rsyslog will create logfiles that do not already exist on the system. This setting controls what permissions will be applied to 79 | these newly created files. 80 | 81 | Rationale: It is important to ensure that log files have the correct permissions to ensure that sensitive data is archived and protected. 82 | ' 83 | impact 1.0 84 | 85 | tag cis: 'distribution-independent-linux:4.2.1.4' 86 | tag level: 1 87 | 88 | # ryslog default file permissions are '0644' 89 | # ref: https://www.rsyslog.com/doc/v8-stable/configuration/action/rsconf1_filecreatemode.html 90 | 91 | # /etc/rsyslog.conf Global config should be set 92 | # 0640 or more restrictive 93 | describe file('/etc/rsyslog.conf') do 94 | its('content') { should match(/^\$FileCreateMode\s+0[0-6][0-4]0/) } 95 | end 96 | 97 | ## individual service config shouldn't overwrite /etc/rsyslog.conf - Legacy 98 | rsyslogd_files = command('grep -l ^\$FileCreateMode /etc/rsyslog.d/*.conf').stdout 99 | 100 | rsyslogd_files.each_line do |filename| 101 | describe file(filename) do 102 | its('content') { should match(/^\$FileCreateMode\s+0[0-6][0-4]0/) } 103 | end 104 | end 105 | 106 | # Check the new RainerScript format in addition to the 'legacy' rsyslog syntax 107 | # which is documented as 'obsolete' 108 | # ref: https://www.rsyslog.com/doc/v8-stable/configuration/modules/omfile.html#filecreatemode 109 | new_rsyslog_conf = command('grep -orE \'FileCreateMode="[0-7]{4}"\' /etc/rsyslog.*').stdout 110 | new_rsyslog_conf.each_line do |result| 111 | filename = result.split(':')[0] 112 | describe file(filename) do 113 | its('content') { should match(/FileCreateMode="0[0-6][0-4]0"/) } 114 | end 115 | end 116 | end 117 | 118 | control 'cis-dil-benchmark-4.2.1.5' do 119 | title 'Ensure rsyslog is configured to send logs to a remote log host' 120 | desc ' 121 | The `rsyslog` utility supports the ability to send logs it gathers to a remote log host running `syslogd(8)` or to 122 | receive messages from remote hosts, reducing administrative overhead. 123 | ' 124 | 125 | impact 1.0 126 | 127 | tag cis: 'distribution-independent-linux:4.2.1.5' 128 | tag level: 1 129 | 130 | describe file('/etc/rsyslog.conf') do 131 | its(:content) { should match(/^\s*\*\.\*\s+@/) } 132 | end 133 | end 134 | 135 | control 'cis-dil-benchmark-4.2.1.6' do 136 | title 'Ensure remote rsyslog messages are only accepted on designated log hosts.' 137 | desc ' 138 | By default, rsyslog does not listen for log messages coming in from remote systems. 139 | The ModLoad tells rsyslog to load the imtcp.so module so it can listen over a network via TCP. 140 | The InputTCPServerRun option instructs rsyslogd to listen on the specified TCP port. 141 | 142 | Rationale: The guidance in the section ensures that remote log hosts are configured to only accept rsyslog 143 | data from hosts within the specified domain and that those systems that are not designed to be log hosts 144 | do not accept any remote rsyslog messages. This provides protection from spoofed log data and ensures 145 | that system administrators are reviewing reasonably complete syslog data in a central location. 146 | ' 147 | impact 0.0 148 | 149 | tag cis: 'distribution-independent-linux:4.2.1.6' 150 | tag level: 1 151 | 152 | describe 'cis-dil-benchmark-4.2.1.6' do 153 | skip 'Not implemented' 154 | end 155 | end 156 | 157 | control 'cis-dil-benchmark-4.2.2.1' do 158 | title 'Ensure journald is configured to send logs to rsyslog' 159 | desc ' 160 | Data from journald may be stored in volatile memory or persisted locally on the server. 161 | Utilities exist to accept remote export of journald logs, however, use of the rsyslog service 162 | provides a consistent means of log collection and export. 163 | ' 164 | impact 1.0 165 | 166 | tag cis: 'distribution-independent-linux:4.2.2.1' 167 | tag level: 1 168 | 169 | # '/etc/systemd/journald.conf' 170 | describe parse_config_file('/etc/systemd/journald.conf') do 171 | its('Journal') { should include({ 'ForwardToSyslog' => 'yes' }) } 172 | end 173 | end 174 | 175 | control 'cis-dil-benchmark-4.2.2.2' do 176 | title 'Ensure journald is configured to compress large log files' 177 | desc ' 178 | The journald system includes the capability of compressing overly large files to 179 | avoid filling up the system with logs or making the logs unmanageably large. 180 | ' 181 | impact 1.0 182 | 183 | tag cis: 'distribution-independent-linux:4.2.2.2' 184 | tag level: 1 185 | 186 | # '/etc/systemd/journald.conf' 187 | describe parse_config_file('/etc/systemd/journald.conf') do 188 | its('Journal') { should include({ 'Compress' => 'yes' }) } 189 | end 190 | end 191 | 192 | control 'cis-dil-benchmark-4.2.2.3' do 193 | title 'Ensure journald is configured to write logfiles to persistent disk' 194 | desc ' 195 | Data from journald may be stored in volatile memory or persisted locally on the server. 196 | Logs in memory will be lost upon a system reboot. By persisting logs to local disk on the 197 | server they are protected from loss. 198 | ' 199 | impact 1.0 200 | 201 | tag cis: 'distribution-independent-linux:4.2.2.3' 202 | tag level: 1 203 | 204 | describe parse_config_file('/etc/systemd/journald.conf') do 205 | its('Journal') { should include({ 'Storage' => 'persistent' }) } 206 | end 207 | end 208 | 209 | control 'cis-dil-benchmark-4.2.3' do 210 | title 'Ensure permissions on all logfiles are configured' 211 | desc ' 212 | Log files stored in /var/log/ contain logged information from many services on the system, 213 | or on log hosts others as well. 214 | ' 215 | impact 1.0 216 | 217 | tag cis: 'distribution-independent-linux:4.2.3' 218 | tag level: 1 219 | 220 | group_write_excepts = %w(lastlog wtmp btmp) 221 | 222 | # wtmp needs other read for `last`, `who`, `w` commands 223 | # lastlog needs other read for `lastlog` command 224 | other_read_excepts = %w(lastlog wtmp) 225 | 226 | command('find /var/log -type f').stdout.split.each do |f| 227 | describe file(f) do 228 | it { should_not be_writable.by 'group' } unless group_write_excepts.include?(f.split('/')[-1]) 229 | it { should_not be_executable.by 'group' } 230 | it { should_not be_readable.by 'other' } unless other_read_excepts.include?(f.split('/')[-1]) 231 | it { should_not be_writable.by 'other' } 232 | it { should_not be_executable.by 'other' } 233 | end 234 | end 235 | end 236 | 237 | control 'cis-dil-benchmark-4.3' do 238 | title 'Ensure logrotate is configured' 239 | desc "The system includes the capability of rotating log files regularly to avoid filling up the system with logs or making the logs unmanageable large. The file /etc/logrotate.d/syslog is the configuration file used to rotate log files created by syslog or rsyslog.\n\nRationale: By keeping the log files smaller and more manageable, a system administrator can easily archive these files to another system and spend less time looking through inordinately large log files." 240 | impact 0.0 241 | 242 | tag cis: 'distribution-independent-linux:4.3' 243 | tag level: 1 244 | 245 | describe 'cis-dil-benchmark-4.3' do 246 | skip 'Not implemented' 247 | end 248 | end 249 | -------------------------------------------------------------------------------- /controls/5_1_configure_cron.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '5.1 Configure cron' 21 | 22 | control 'cis-dil-benchmark-5.1.1' do 23 | title 'Ensure cron daemon is enabled' 24 | desc ' 25 | The cron daemon is used to execute batch jobs on the system. 26 | 27 | Rationale: 28 | 29 | While there may not be user jobs that need to be run on the system, the system does have maintenance jobs that may include 30 | security monitoring that have to run, and cron is used to execute them. 31 | ' 32 | impact 1.0 33 | 34 | tag cis: 'distribution-independent-linux:5.1.1' 35 | tag level: 1 36 | 37 | describe.one do 38 | %w(cron crond).each do |s| 39 | describe service(s) do 40 | it { should be_enabled } 41 | it { should be_running } 42 | end 43 | end 44 | end 45 | end 46 | 47 | control 'cis-dil-benchmark-5.1.2' do 48 | title 'Ensure permissions on /etc/crontab are configured' 49 | desc ' 50 | The /etc/crontab file is used by cron to control its own jobs. The commands in this item make sure that root 51 | is the user and group owner of the file and that only the owner can access the file. 52 | 53 | Rationale: 54 | 55 | This file contains information on what system jobs are run by cron. Write access to these files could provide 56 | unprivileged users with the ability to elevate their privileges. Read access to these files could provide user 57 | with the ability to gain insight on system jobs that run on the system and could provide them a way to gain 58 | unauthorized privileged access. 59 | ' 60 | impact 1.0 61 | 62 | tag cis: 'distribution-independent-linux:5.1.2' 63 | tag level: 1 64 | 65 | describe file('/etc/crontab') do 66 | it { should exist } 67 | it { should_not be_readable.by 'group' } 68 | it { should_not be_writable.by 'group' } 69 | it { should_not be_executable.by 'group' } 70 | it { should_not be_readable.by 'other' } 71 | it { should_not be_writable.by 'other' } 72 | it { should_not be_executable.by 'other' } 73 | it { should be_owned_by 'root' } 74 | it { should be_grouped_into 'root' } 75 | end 76 | end 77 | 78 | control 'cis-dil-benchmark-5.1.3' do 79 | title 'Ensure permissions on /etc/cron.hourly are configured' 80 | desc ' 81 | This directory contains system cron jobs that need to run on an hourly basis. The files in this 82 | directory cannot be manipulated by the crontab command, but are instead edited by system administrators 83 | using a text editor. The commands below restrict read/write and search access to user and group root, 84 | preventing regular users from accessing this directory. 85 | 86 | Rationale: 87 | 88 | Granting write access to this directory for non-privileged users could provide them the means 89 | for gaining unauthorized elevated privileges. Granting read access to this directory could give 90 | an unprivileged user insight in how to gain elevated privileges or circumvent auditing controls. 91 | ' 92 | impact 1.0 93 | 94 | tag cis: 'distribution-independent-linux:5.1.3' 95 | tag level: 1 96 | 97 | describe file('/etc/cron.hourly') do 98 | it { should exist } 99 | it { should_not be_readable.by 'group' } 100 | it { should_not be_writable.by 'group' } 101 | it { should_not be_executable.by 'group' } 102 | it { should_not be_readable.by 'other' } 103 | it { should_not be_writable.by 'other' } 104 | it { should_not be_executable.by 'other' } 105 | it { should be_owned_by 'root' } 106 | it { should be_grouped_into 'root' } 107 | end 108 | end 109 | 110 | control 'cis-dil-benchmark-5.1.4' do 111 | title 'Ensure permissions on /etc/cron.daily are configured' 112 | desc ' 113 | The /etc/cron.daily directory contains system cron jobs that need to run on a daily basis. 114 | The files in this directory cannot be manipulated by the crontab command, but are instead edited 115 | by system administrators using a text editor. The commands below restrict read/write and search 116 | access to user and group root, preventing regular users from accessing this directory. 117 | 118 | Rationale: 119 | 120 | Granting write access to this directory for non-privileged users could provide them the means for gaining 121 | unauthorized elevated privileges. Granting read access to this directory could give an unprivileged user 122 | insight in how to gain elevated privileges or circumvent auditing controls. 123 | ' 124 | impact 1.0 125 | 126 | tag cis: 'distribution-independent-linux:5.1.4' 127 | tag level: 1 128 | 129 | describe file('/etc/cron.daily') do 130 | it { should exist } 131 | it { should_not be_readable.by 'group' } 132 | it { should_not be_writable.by 'group' } 133 | it { should_not be_executable.by 'group' } 134 | it { should_not be_readable.by 'other' } 135 | it { should_not be_writable.by 'other' } 136 | it { should_not be_executable.by 'other' } 137 | it { should be_owned_by 'root' } 138 | it { should be_grouped_into 'root' } 139 | end 140 | end 141 | 142 | control 'cis-dil-benchmark-5.1.5' do 143 | title 'Ensure permissions on /etc/cron.weekly are configured' 144 | desc ' 145 | The /etc/cron.weekly directory contains system cron jobs that need to run on a weekly basis. The files 146 | in this directory cannot be manipulated by the crontab command, but are instead edited by system 147 | administrators using a text editor. The commands below restrict read/write and search access to user 148 | and group root, preventing regular users from accessing this directory. 149 | 150 | Rationale: 151 | 152 | Granting write access to this directory for non-privileged users could provide them the means for gaining 153 | unauthorized elevated privileges. Granting read access to this directory could give an unprivileged user 154 | insight in how to gain elevated privileges or circumvent auditing controls. 155 | ' 156 | impact 1.0 157 | 158 | tag cis: 'distribution-independent-linux:5.1.5' 159 | tag level: 1 160 | 161 | describe file('/etc/cron.weekly') do 162 | it { should exist } 163 | it { should_not be_readable.by 'group' } 164 | it { should_not be_writable.by 'group' } 165 | it { should_not be_executable.by 'group' } 166 | it { should_not be_readable.by 'other' } 167 | it { should_not be_writable.by 'other' } 168 | it { should_not be_executable.by 'other' } 169 | it { should be_owned_by 'root' } 170 | it { should be_grouped_into 'root' } 171 | end 172 | end 173 | 174 | control 'cis-dil-benchmark-5.1.6' do 175 | title 'Ensure permissions on /etc/cron.monthly are configured' 176 | desc ' 177 | The /etc/cron.monthly directory contains system cron jobs that need to run on a monthly basis. The files 178 | in this directory cannot be manipulated by the crontab command, but are instead edited by system 179 | administrators using a text editor. The commands below restrict read/write and search access to user and 180 | group root, preventing regular users from accessing this directory. 181 | 182 | Rationale: 183 | 184 | Granting write access to this directory for non-privileged users could provide them the means for gaining 185 | unauthorized elevated privileges. Granting read access to this directory could give an unprivileged user 186 | insight in how to gain elevated privileges or circumvent auditing controls. 187 | ' 188 | impact 1.0 189 | 190 | tag cis: 'distribution-independent-linux:5.1.6' 191 | tag level: 1 192 | 193 | describe file('/etc/cron.monthly') do 194 | it { should exist } 195 | it { should_not be_readable.by 'group' } 196 | it { should_not be_writable.by 'group' } 197 | it { should_not be_executable.by 'group' } 198 | it { should_not be_readable.by 'other' } 199 | it { should_not be_writable.by 'other' } 200 | it { should_not be_executable.by 'other' } 201 | it { should be_owned_by 'root' } 202 | it { should be_grouped_into 'root' } 203 | end 204 | end 205 | 206 | control 'cis-dil-benchmark-5.1.7' do 207 | title 'Ensure permissions on /etc/cron.d are configured' 208 | desc ' 209 | The /etc/cron.d directory contains system cron jobs that need to run in a similar manner to the hourly, 210 | daily weekly and monthly jobs from /etc/crontab, but require more granular control as to when they run. 211 | The files in this directory cannot be manipulated by the crontab command, but are instead edited by system 212 | administrators using a text editor. The commands below restrict read/write and search access to user and group 213 | root, preventing regular users from accessing this directory. 214 | 215 | Rationale: 216 | 217 | Granting write access to this directory for non-privileged users could provide them the means for gaining unauthorized 218 | elevated privileges. Granting read access to this directory could give an unprivileged user insight in how to gain 219 | elevated privileges or circumvent auditing controls. 220 | ' 221 | impact 1.0 222 | 223 | tag cis: 'distribution-independent-linux:5.1.7' 224 | tag level: 1 225 | 226 | describe file('/etc/cron.d') do 227 | it { should exist } 228 | it { should_not be_readable.by 'group' } 229 | it { should_not be_writable.by 'group' } 230 | it { should_not be_executable.by 'group' } 231 | it { should_not be_readable.by 'other' } 232 | it { should_not be_writable.by 'other' } 233 | it { should_not be_executable.by 'other' } 234 | it { should be_owned_by 'root' } 235 | it { should be_grouped_into 'root' } 236 | end 237 | end 238 | 239 | control 'cis-dil-benchmark-5.1.8' do 240 | title 'Ensure at/cron is restricted to authorized users' 241 | desc ' 242 | Configure /etc/cron.allow and /etc/at.allow to allow specific users to use these services. 243 | If /etc/cron.allow or /etc/at.allow do not exist, then /etc/at.deny and /etc/cron.deny are checked. 244 | Any user not specifically defined in those files is allowed to use at and cron. By removing the files, 245 | only users in /etc/cron.allow and /etc/at.allow are allowed to use at and cron. 246 | 247 | Note that even though a given user is not listed in cron.allow, cron jobs can still be run as that user. 248 | The cron.allow file only controls administrative access to the crontab command for scheduling and modifying 249 | cron jobs. 250 | 251 | Rationale: 252 | 253 | On many systems, only the system administrator is authorized to schedule cron jobs. Using the cron.allow file 254 | to control who can run cron jobs enforces this policy. It is easier to manage an allow list than a deny list. 255 | In a deny list, you could potentially add a user ID to the system and forget to add it to the deny files. 256 | ' 257 | impact 1.0 258 | 259 | tag cis: 'distribution-independent-linux:5.1.8' 260 | tag level: 1 261 | 262 | %w(cron at).each do |s| 263 | describe file("/etc/#{s}.deny") do 264 | it { should_not exist } 265 | end 266 | 267 | describe file("/etc/#{s}.allow") do 268 | it { should exist } 269 | it { should_not be_readable.by 'group' } 270 | it { should_not be_writable.by 'group' } 271 | it { should_not be_executable.by 'group' } 272 | it { should_not be_readable.by 'other' } 273 | it { should_not be_writable.by 'other' } 274 | it { should_not be_executable.by 'other' } 275 | it { should be_owned_by 'root' } 276 | it { should be_grouped_into 'root' } 277 | end 278 | end 279 | end 280 | -------------------------------------------------------------------------------- /controls/5_3_configure_pam.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '5.3 Configure PAM' 21 | 22 | control 'cis-dil-benchmark-5.3.1' do 23 | title 'Ensure password creation requirements are configured' 24 | desc ' 25 | The pam_cracklib.so module checks the strength of passwords. It performs 26 | checks such as making sure a password is not a dictionary word, it is a 27 | certain length, contains a mix of characters (e.g. alphabet, numeric, other) 28 | and more. The following are definitions of the pam_cracklib.so options. 29 | 30 | * try_first_pass - retrieve the password from a previous stacked PAM module. 31 | If not available, then prompt the user for a password. 32 | * retry=3 - Allow 3 tries before sending back a failure. 33 | * minlen=14 - password must be 14 characters or more 34 | * dcredit=-1 - provide at least one digit 35 | * ucredit=-1 - provide at least one uppercase character 36 | * ocredit=-1 - provide at least one special character 37 | * lcredit=-1 - provide at least one lowercase character 38 | 39 | The pam_pwquality.so module functions similarly but the minlen, dcredit, 40 | ucredit , ocredit , and lcredit parameters are stored in the 41 | /etc/security/pwquality.conf file. The settings shown above are one possible 42 | policy. Alter these values to conform to your own organization`s password 43 | policies. 44 | 45 | Rationale: Strong passwords protect systems from being hacked through brute 46 | force methods. 47 | ' 48 | 49 | impact 1.0 50 | 51 | tag cis: 'distribution-independent-linux:5.3.1' 52 | tag level: 1 53 | 54 | if package('pam_cracklib').installed? 55 | describe.one do 56 | %w(common-password system-auth).each do |f| 57 | describe file("/etc/pam.d/#{f}") do 58 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*try_first_pass/) } 59 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*retry=[3210]/) } 60 | end 61 | end 62 | end 63 | 64 | describe.one do 65 | %w(common-password system-auth).each do |f| 66 | describe file("/etc/pam.d/#{f}") do 67 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*minlen=(1[4-9]|[2-9][0-9]|[1-9][0-9][0-9]+)/) } 68 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*dcredit=-[1-9][0-9]*\s*(?:#.*)?/) } 69 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*lcredit=-[1-9][0-9]*\s*(?:#.*)?/) } 70 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*ucredit=-[1-9][0-9]*\s*(?:#.*)?/) } 71 | its('content') { should match(/^password\s+required\s+pam_cracklib\.so (\S+\s+)*ocredit=-[1-9][0-9]*\s*(?:#.*)?/) } 72 | end 73 | end 74 | end 75 | end 76 | 77 | if package('pam_passwdqc').installed? || package('libpwquality').installed? 78 | describe.one do 79 | %w(common-password system-auth).each do |f| 80 | describe file("/etc/pam.d/#{f}") do 81 | its('content') { should match(/^password\s+requisite\s+pam_pwquality\.so (\S+\s+)*retry=[3210]/) } 82 | its('content') { should match(/^password\s+requisite\s+pam_pwquality\.so (\S+\s+)*try_first_pass/) } 83 | end 84 | end 85 | end 86 | 87 | describe file('/etc/security/pwquality.conf') do 88 | its('content') { should match(/^minlen = (1[4-9]|[2-9][0-9]|[1-9][0-9][0-9]+)\s*(?:#.*)?$/) } 89 | its('content') { should match(/^dcredit = -[1-9][0-9]*\s*(?:#.*)?$/) } 90 | its('content') { should match(/^lcredit = -[1-9][0-9]*\s*(?:#.*)?$/) } 91 | its('content') { should match(/^ucredit = -[1-9][0-9]*\s*(?:#.*)?$/) } 92 | its('content') { should match(/^ocredit = -[1-9][0-9]*\s*(?:#.*)?$/) } 93 | end 94 | end 95 | end 96 | 97 | control 'cis-dil-benchmark-5.3.2' do 98 | title 'Ensure lockout for failed password attempts is configured' 99 | desc ' 100 | Lock out users after n unsuccessful consecutive login attempts. The first 101 | sets of changes are made to the PAM configuration files. The second set of 102 | changes are applied to the program specific PAM configuration file. The 103 | second set of changes must be applied to each program that will lock out 104 | users. Check the documentation for each secondary program for instructions 105 | on how to configure them to work with PAM. 106 | Set the lockout number to the policy in effect at your site. 107 | 108 | Rationale: Locking out user IDs after n unsuccessful consecutive login 109 | attempts mitigates brute force password attacks against your systems. 110 | ' 111 | 112 | impact 0.0 113 | 114 | tag cis: 'distribution-independent-linux:5.3.2' 115 | tag level: 1 116 | 117 | describe 'cis-dil-benchmark-5.3.2' do 118 | skip 'Not implemented' 119 | end 120 | end 121 | 122 | control 'cis-dil-benchmark-5.3.3' do 123 | title 'Ensure password reuse is limited' 124 | desc ' 125 | The /etc/security/opasswd file stores the users` old passwords and can be 126 | checked to ensure that users are not recycling recent passwords. 127 | 128 | Rationale: Forcing users not to reuse their past 5 passwords make it less 129 | likely that an attacker will be able to guess the password. Note that these 130 | change only apply to accounts configured on the local system. 131 | ' 132 | 133 | impact 0.0 134 | 135 | tag cis: 'distribution-independent-linux:5.3.3' 136 | tag level: 1 137 | 138 | describe.one do 139 | %w(common-password system-auth).each do |f| 140 | describe file("/etc/pam.d/#{f}") do 141 | its('content') { should match(/^password\s+(\S+\s+)+pam_unix\.so (\S+\s+)*remember=([56789]|[1-9][0-9]+)/) } 142 | end 143 | 144 | describe file("/etc/pam.d/#{f}") do 145 | its('content') { should match(/^password\s+(\S+\s+)+pam_pwhistory\.so (\S+\s+)*remember=([56789]|[1-9][0-9]+)/) } 146 | end 147 | end 148 | end 149 | end 150 | 151 | control 'cis-dil-benchmark-5.3.4' do 152 | title 'Ensure password hashing algorithm is SHA-512' 153 | desc ' 154 | The commands below change password encryption from md5 to sha512 (a much 155 | stronger hashing algorithm). All existing accounts will need to perform 156 | a password change to upgrade the stored hashes to the new algorithm. 157 | 158 | Rationale: The SHA-512 algorithm provides much stronger hashing than MD5, 159 | thus providing additional protection to the system by increasing the level 160 | of effort for an attacker to successfully determine passwords. Note that 161 | these change only apply to accounts configured on the local system. 162 | ' 163 | 164 | impact 0.0 165 | 166 | tag cis: 'distribution-independent-linux:5.3.4' 167 | tag level: 1 168 | 169 | describe.one do 170 | %w(common-password system-auth password-auth).each do |f| 171 | describe file("/etc/pam.d/#{f}") do 172 | its('content') { should match(/^password\s+(\S+\s+)+pam_unix\.so\s+(\S+\s+)*sha512/) } 173 | end 174 | end 175 | end 176 | end 177 | -------------------------------------------------------------------------------- /controls/5_4_user_accounts_and_environments.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | cis_level = input('cis_level') 21 | 22 | title '5.4 User Accounts and Environments' 23 | 24 | shadow_files = ['/etc/shadow'] 25 | shadow_files << '/usr/share/baselayout/shadow' if file('/etc/nsswitch.conf').content =~ /^shadow:\s+(\S+\s+)*usrfiles/ 26 | 27 | passwd_files = ['/etc/passwd'] 28 | passwd_files << '/usr/share/baselayout/passwd' if file('/etc/nsswitch.conf').content =~ /^passwd:\s+(\S+\s+)*usrfiles/ 29 | 30 | shell_config_files = %w(bash.bashrc profile bashrc).map { |f| "/etc/#{f}" }.select { |f| file(f).file? } 31 | 32 | control 'cis-dil-benchmark-5.4.1.1' do 33 | title 'Ensure password expiration is 365 days or less' 34 | desc "The PASS_MAX_DAYS parameter in /etc/login.defs allows an administrator to force passwords to expire once they reach a defined age. It is recommended that the PASS_MAX_DAYS parameter be set to less than or equal to 365 days.\n\nRationale: The window of opportunity for an attacker to leverage compromised credentials or successfully compromise credentials via an online brute force attack is limited by the age of the password. Therefore, reducing the maximum age of a password also reduces an attacker's window of opportunity." 35 | impact 1.0 36 | 37 | tag cis: 'distribution-independent-linux:5.4.1.1' 38 | tag level: 1 39 | 40 | describe login_defs do 41 | its('PASS_MAX_DAYS') { should cmp <= 365 } 42 | end 43 | 44 | shadow_files.each do |f| 45 | shadow(f).users(/.+/).entries.each do |user| 46 | next if user.password =~ /^[!*]/ 47 | 48 | describe user do 49 | its('max_days') { should cmp <= 365 } 50 | end 51 | end 52 | end 53 | end 54 | 55 | control 'cis-dil-benchmark-5.4.1.2' do 56 | title 'Ensure minimum days between password changes is 7 or more' 57 | desc "The PASS_MIN_DAYS parameter in /etc/login.defs allows an administrator to prevent users from changing their password until a minimum number of days have passed since the last time the user changed their password. It is recommended that PASS_MIN_DAYS parameter be set to 7 or more days.\n\nRationale: By restricting the frequency of password changes, an administrator can prevent users from repeatedly changing their password in an attempt to circumvent password reuse controls." 58 | impact 1.0 59 | 60 | tag cis: 'distribution-independent-linux:5.4.1.2' 61 | tag level: 1 62 | 63 | describe login_defs do 64 | its('PASS_MIN_DAYS') { should cmp >= 7 } 65 | end 66 | 67 | shadow_files.each do |f| 68 | shadow(f).users(/.+/).entries.each do |user| 69 | next if user.password =~ /^[!*]/ 70 | 71 | describe user do 72 | its('min_days') { should cmp >= 7 } 73 | end 74 | end 75 | end 76 | end 77 | 78 | control 'cis-dil-benchmark-5.4.1.3' do 79 | title 'Ensure password expiration warning days is 7 or more' 80 | desc "The PASS_WARN_AGE parameter in /etc/login.defs allows an administrator to notify users that their password will expire in a defined number of days. It is recommended that the PASS_WARN_AGE parameter be set to 7 or more days.\n\nRationale: Providing an advance warning that a password will be expiring gives users time to think of a secure password. Users caught unaware may choose a simple password or write it down where it may be discovered." 81 | impact 1.0 82 | 83 | tag cis: 'distribution-independent-linux:5.4.1.3' 84 | tag level: 1 85 | 86 | describe login_defs do 87 | its('PASS_WARN_AGE') { should cmp >= 7 } 88 | end 89 | 90 | shadow_files.each do |f| 91 | shadow(f).users(/.+/).entries.each do |user| 92 | next if user.password =~ /^[!*]/ 93 | 94 | describe user do 95 | its('warn_days') { should cmp >= 7 } 96 | end 97 | end 98 | end 99 | end 100 | 101 | control 'cis-dil-benchmark-5.4.1.4' do 102 | title 'Ensure inactive password lock is 30 days or less' 103 | desc "User accounts that have been inactive for over a given period of time can be automatically disabled. It is recommended that accounts that are inactive for 30 days after password expiration be disabled.\n\nRationale: Inactive accounts pose a threat to system security since the users are not logging in to notice failed login attempts or other anomalies." 104 | impact 1.0 105 | 106 | tag cis: 'distribution-independent-linux:5.4.1.4' 107 | tag level: 1 108 | 109 | describe command('useradd -D') do 110 | its('stdout') { should match(/^INACTIVE=(30|[1-2][0-9]|[1-9])$/) } 111 | end 112 | 113 | shadow_files.each do |f| 114 | shadow(f).users(/.+/).entries.each do |user| 115 | next if user.password =~ /^[!*]/ 116 | 117 | describe user do 118 | its('inactive_days') { should cmp <= 30 } 119 | end 120 | end 121 | end 122 | end 123 | 124 | control 'cis-dil-benchmark-5.4.1.5' do 125 | title 'Ensure all users last password change date is in the past' 126 | desc "All users should have a password change date in the past. \n\nRationale: If a users recorded password change date is in the future then they could bypass any set password expiration." 127 | impact 1.0 128 | 129 | tag cis: 'distribution-independent-linux:5.4.1.5' 130 | tag level: 1 131 | 132 | days_since_epoch = Date.today.to_time.to_i / (60 * 60 * 24) 133 | 134 | shadow_files.each do |f| 135 | shadow(f).users(/.+/).entries.each do |user| 136 | next if user.password =~ /^[!*]/ 137 | 138 | describe user do 139 | its('last_change') { should cmp <= days_since_epoch } 140 | end 141 | end 142 | end 143 | end 144 | 145 | control 'cis-dil-benchmark-5.4.2' do 146 | title 'Ensure system accounts are secured' 147 | desc "There are a number of accounts provided with Ubuntu that are used to manage applications and are not intended to provide an interactive shell.\n\nRationale: It is important to make sure that accounts that are not being used by regular users are prevented from being used to provide an interactive shell. By default, Ubuntu sets the password field for these accounts to an invalid string, but it is also recommended that the shell field in the password file be set to /sbin/nologin. This prevents the account from potentially being used to run any commands." 148 | impact 1.0 149 | 150 | tag cis: 'distribution-independent-linux:5.4.2' 151 | tag level: 1 152 | 153 | uid_min = login_defs.UID_MIN.to_i 154 | 155 | passwd_files.each do |f| 156 | passwd(f).where { uid.to_i < uid_min }.entries.each do |user| 157 | next if %w(root sync shutdown halt).include? user.user 158 | 159 | describe user do 160 | its('shell') { should match(%r{(/usr/sbin/nologin|/sbin/nologin|/bin/false)}) } 161 | end 162 | 163 | describe shadow.where(user: user.user) do 164 | its('passwords') { should cmp(/^[*!]/) } 165 | end 166 | end 167 | end 168 | end 169 | 170 | control 'cis-dil-benchmark-5.4.3' do 171 | title 'Ensure default group for the root account is GID 0' 172 | desc "The usermod command can be used to specify which group the root user belongs to. This affects permissions of files that are created by the root user.\n\nRationale: Using GID 0 for the root account helps prevent root -owned files from accidentally becoming accessible to non-privileged users." 173 | impact 1.0 174 | 175 | tag cis: 'distribution-independent-linux:5.4.3' 176 | tag level: 1 177 | 178 | describe passwd.users('root') do 179 | its('gids') { should cmp 0 } 180 | end 181 | end 182 | 183 | control 'cis-dil-benchmark-5.4.4' do 184 | title 'Ensure default user umask is 027 or more restrictive' 185 | desc "The default umask determines the permissions of files created by users. The user creating the file has the discretion of making their files and directories readable by others via the chmod command. Users who wish to allow their files and directories to be readable by others by default may choose a different default umask by inserting the umask command into the standard shell configuration files (.profile, .bashrc, etc.) in their home directories.\n\nRationale: Setting a very secure default value for umask ensures that users make a conscious choice about their file permissions. A default umask setting of 077 causes files and directories created by users to not be readable by any other user on the system. A umask of 027 would make files and directories readable by users in the same Unix group, while a umask of 022 would make files readable by every user on the system." 186 | impact 1.0 187 | 188 | tag cis: 'distribution-independent-linux:5.4.4' 189 | tag level: 1 190 | 191 | shell_config_files.each do |f| 192 | describe file(f) do 193 | its('content') { should_not match(/^\s*umask [0-7](0[1-7]|[1-7][1-6])\s*(?:#.*)?$/) } 194 | its('content') { should match(/^\s*umask [0-7][2367]7\s*(?:#.*)?$/) } 195 | end 196 | end 197 | end 198 | 199 | control 'cis-dil-benchmark-5.4.5' do 200 | title 'Ensure default user shell timeout is 900 seconds or less' 201 | desc "The default TMOUT determines the shell timeout for users. The TMOUT value is measured in seconds.\n\nRationale: Having no timeout value associated with a shell could allow an unauthorized user access to another user's shell session (e.g. user walks away from their computer and doesn't lock the screen). Setting a timeout value at least reduces the risk of this happening." 202 | impact 1.0 203 | 204 | tag cis: 'distribution-independent-linux:5.4.5' 205 | tag level: 2 206 | 207 | shell_config_files.each do |f| 208 | describe file(f) do 209 | its('content') { should match(/^\s*TMOUT=([0-8][0-9]{0,2}|900)\s*(?:#.*)?$/) } 210 | end 211 | end 212 | 213 | only_if { cis_level == 2 } 214 | end 215 | 216 | control 'cis-dil-benchmark-5.5' do 217 | title 'Ensure root login is restricted to system console' 218 | desc "The file /etc/securetty contains a list of valid terminals that may be logged in directly as root.\n\nRationale: Since the system console has special properties to handle emergency situations, it is important to ensure that the console is in a physically secure location and that unauthorized consoles have not been defined." 219 | impact 0.0 220 | 221 | tag cis: 'distribution-independent-linux:5.5' 222 | tag level: 1 223 | 224 | describe 'cis-dil-benchmark-5.5' do 225 | skip 'Not implemented' 226 | end 227 | end 228 | 229 | control 'cis-dil-benchmark-5.6' do 230 | title 'Ensure access to the su command is restricted' 231 | desc "The su command allows a user to run a command or shell as another user. The program has been superseded by sudo, which allows for more granular control over privileged access. Normally, the su command can be executed by any user. By uncommenting the pam_wheel.so statement in /etc/pam.d/su, the su command will only allow users in the wheel group to execute su.\n\nRationale: Restricting the use of su, and using sudo in its place, provides system administrators better control of the escalation of user privileges to execute privileged commands. The sudo utility also provides a better logging and audit mechanism, as it can log each command executed via sudo, whereas su can only record that a user executed the su program." 232 | impact 1.0 233 | 234 | tag cis: 'distribution-independent-linux:5.6' 235 | tag level: 1 236 | 237 | describe file('/etc/pam.d/su') do 238 | its('content') { should match(/^auth\s+required\s+pam_wheel.so use_uid$/) } 239 | end 240 | end 241 | -------------------------------------------------------------------------------- /controls/6_1_system_file_permissions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | cis_level = input('cis_level') 21 | 22 | expected_gid = 0 23 | expected_gid = 42 if os.debian? || os.suse? || os.name == 'alpine' 24 | 25 | title '6.1 System File Permissions' 26 | 27 | control 'cis-dil-benchmark-6.1.1' do 28 | title 'Audit system file permissions' 29 | desc ' 30 | The RPM and Debian package manager have a number of useful options. One of these, the --verify 31 | (or -v for RPM) option, can be used to verify that system packages are correctly installed. The --verify 32 | option can be used to verify a particular package or to verify all system packages. If no output is 33 | returned, the package is installed correctly. The following table describes the meaning of output 34 | from the verify option: 35 | 36 | Code Meaning 37 | S File size differs. 38 | M File mode differs (includes permissions and file type). 39 | 5 The MD5 checksum differs. 40 | D The major and minor version numbers differ on a device file. 41 | L A mismatch occurs in a link. 42 | U The file ownership differs. 43 | G The file group owner differs. 44 | T The file time (mtime) differs. 45 | 46 | The `rpm -qf` or `dpkg -S` command can be used to determine which package a particular file belongs to. 47 | For example the following commands determines which package the /bin/bash file belongs to: 48 | ```shell-session 49 | # rpm -qf /bin/bash 50 | bash-4.1.2-29.el6.x86_64 51 | 52 | # dpkg -S /bin/bash 53 | bash: /bin/bash 54 | ``` 55 | 56 | To verify the settings for the package that controls the /bin/bash file, run the following: 57 | ```shell-session 58 | # rpm -V bash-4.1.2-29.el6.x86_64 59 | .M....... /bin/bash 60 | 61 | # dpkg --verify bash 62 | ??5?????? c /etc/bash.bashrc 63 | ``` 64 | 65 | Note that you can feed the output of the rpm -qf command to the rpm -V command: 66 | ```shell-session 67 | # rpm -V `rpm -qf /etc/passwd` 68 | .M...... c /etc/passwd\nS.5....T c /etc/printcap 69 | ``` 70 | Rationale: 71 | It is important to confirm that packaged system files and directories are maintained with the permissions 72 | they were intended to have from the OS vendor. 73 | ' 74 | impact 0.0 75 | 76 | tag cis: 'distribution-independent-linux:6.1.1' 77 | tag level: 2 78 | 79 | only_if { cis_level == 2 } 80 | 81 | describe 'cis-dil-benchmark-6.1.1' do 82 | skip 'Not implemented' 83 | end 84 | end 85 | 86 | control 'cis-dil-benchmark-6.1.2' do 87 | title 'Ensure permissions on /etc/passwd are configured' 88 | desc ' 89 | The /etc/passwd file contains user account information that is used by many system utilities and 90 | therefore must be readable for these utilities to operate. 91 | 92 | Rationale: 93 | 94 | It is critical to ensure that the /etc/passwd file is protected from unauthorized write access. 95 | Although it is protected by default, the file permissions could be changed either inadvertently or 96 | through malicious actions. 97 | ' 98 | impact 1.0 99 | 100 | tag cis: 'distribution-independent-linux:6.1.2' 101 | tag level: 1 102 | 103 | passwd_files = ['/etc/passwd'] 104 | passwd_files << '/usr/share/baselayout/passwd' if file('/etc/nsswitch.conf').content =~ /^passwd:\s+(\S+\s+)*usrfiles/ 105 | 106 | passwd_files.each do |f| 107 | describe file(f) do 108 | it { should exist } 109 | its('mode') { should cmp '0644' } 110 | it { should be_owned_by 'root' } 111 | it { should be_grouped_into 'root' } 112 | its('sticky') { should equal false } 113 | its('suid') { should equal false } 114 | its('sgid') { should equal false } 115 | end 116 | end 117 | end 118 | 119 | control 'cis-dil-benchmark-6.1.3' do 120 | title 'Ensure permissions on /etc/shadow are configured' 121 | desc ' 122 | The /etc/shadow file is used to store the information about user accounts that is critical to the security 123 | of those accounts, such as the hashed password and other security information. 124 | 125 | Rationale: If attackers can gain read access to the /etc/shadow file, they can easily run a password cracking program 126 | against the hashed password to break it. Other security information that is stored in the /etc/shadow file (such as expiration) 127 | could also be useful to subvert the user accounts. 128 | ' 129 | impact 1.0 130 | 131 | tag cis: 'distribution-independent-linux:6.1.3' 132 | tag level: 1 133 | 134 | shadow_files = ['/etc/shadow'] 135 | shadow_files << '/usr/share/baselayout/shadow' if file('/etc/nsswitch.conf').content =~ /^shadow:\s+(\S+\s+)*usrfiles/ 136 | 137 | shadow_files.each do |f| 138 | describe file(f) do 139 | it { should exist } 140 | it { should_not be_more_permissive_than('0640') } 141 | it { should be_owned_by 'root' } 142 | its('gid') { should cmp expected_gid } 143 | end 144 | end 145 | end 146 | 147 | control 'cis-dil-benchmark-6.1.4' do 148 | title 'Ensure permissions on /etc/group are configured' 149 | desc ' 150 | The /etc/group file contains a list of all the valid groups defined in the system. The command below allows 151 | read/write access for root and read access for everyone else. 152 | 153 | Rationale: 154 | 155 | The /etc/group file needs to be protected from unauthorized changes by non-privileged users, but needs to 156 | be readable as this information is used with many non-privileged programs. 157 | ' 158 | impact 1.0 159 | 160 | tag cis: 'distribution-independent-linux:6.1.4' 161 | tag level: 1 162 | 163 | group_files = ['/etc/group'] 164 | group_files << '/usr/share/baselayout/group' if file('/etc/nsswitch.conf').content =~ /^group:\s+(\S+\s+)*usrfiles/ 165 | 166 | group_files.each do |f| 167 | describe file(f) do 168 | it { should exist } 169 | its('mode') { should cmp '0644' } 170 | it { should be_owned_by 'root' } 171 | it { should be_grouped_into 'root' } 172 | end 173 | end 174 | end 175 | 176 | control 'cis-dil-benchmark-6.1.5' do 177 | title 'Ensure permissions on /etc/gshadow are configured' 178 | desc ' 179 | The /etc/gshadow file is used to store the information about groups that is critical to the security of 180 | those accounts, such as the hashed password and other security information. 181 | 182 | Rationale: 183 | 184 | If attackers can gain read access to the /etc/gshadow file, they can easily run a password cracking program 185 | against the hashed password to break it. Other security information that is stored in the /etc/gshadow file 186 | (such as group administrators) could also be useful to subvert the group. 187 | ' 188 | impact 1.0 189 | 190 | tag cis: 'distribution-independent-linux:6.1.5' 191 | tag level: 1 192 | 193 | gshadow_files = ['/etc/gshadow'] 194 | gshadow_files << '/usr/share/baselayout/gshadow' if file('/etc/nsswitch.conf').content =~ /^gshadow:\s+(\S+\s+)*usrfiles/ 195 | 196 | gshadow_files.each do |f| 197 | describe file(f) do 198 | it { should exist } 199 | it { should_not be_more_permissive_than('0640') } 200 | it { should be_owned_by 'root' } 201 | its('gid') { should cmp expected_gid } 202 | end 203 | end 204 | end 205 | 206 | control 'cis-dil-benchmark-6.1.6' do 207 | title 'Ensure permissions on /etc/passwd- are configured' 208 | desc ' 209 | The /etc/passwd- file contains backup user account information. 210 | 211 | Rationale: 212 | 213 | It is critical to ensure that the /etc/passwd- file is protected from unauthorized access. 214 | Although it is protected by default, the file permissions could be changed either inadvertently or 215 | through malicious actions. 216 | ' 217 | impact 1.0 218 | 219 | tag cis: 'distribution-independent-linux:6.1.6' 220 | tag level: 1 221 | 222 | describe file('/etc/passwd-') do 223 | it { should exist } 224 | it { should_not be_more_permissive_than('0600') } 225 | it { should be_owned_by 'root' } 226 | it { should be_grouped_into 'root' } 227 | end 228 | end 229 | 230 | control 'cis-dil-benchmark-6.1.7' do 231 | title 'Ensure permissions on /etc/shadow- are configured' 232 | desc ' 233 | The /etc/shadow- file is used to store backup information about user accounts that is critical to the security 234 | of those accounts, such as the hashed password and other security information. 235 | 236 | Rationale: 237 | It is critical to ensure that the /etc/shadow- file is protected from unauthorized access. Although it is 238 | protected by default, the file permissions could be changed either inadvertently or through malicious actions. 239 | ' 240 | impact 1.0 241 | 242 | tag cis: 'distribution-independent-linux:6.1.7' 243 | tag level: 1 244 | 245 | describe file('/etc/shadow-') do 246 | it { should exist } 247 | it { should_not be_more_permissive_than('0640') } 248 | 249 | it { should be_owned_by 'root' } 250 | its('gid') { should cmp expected_gid } 251 | end 252 | end 253 | 254 | control 'cis-dil-benchmark-6.1.8' do 255 | title 'Ensure permissions on /etc/group- are configured' 256 | desc ' 257 | The /etc/group- file contains a backup list of all the valid groups defined in the system. 258 | 259 | Rationale: 260 | 261 | It is critical to ensure that the /etc/group- file is protected from unauthorized access. Although it 262 | is protected by default, the file permissions could be changed either inadvertently or through malicious 263 | actions. 264 | ' 265 | impact 1.0 266 | 267 | tag cis: 'distribution-independent-linux:6.1.8' 268 | tag level: 1 269 | 270 | describe file('/etc/group-') do 271 | it { should exist } 272 | it { should_not be_more_permissive_than('0644') } 273 | it { should be_owned_by 'root' } 274 | it { should be_grouped_into 'root' } 275 | end 276 | end 277 | 278 | control 'cis-dil-benchmark-6.1.9' do 279 | title 'Ensure permissions on /etc/gshadow- are configured' 280 | desc ' 281 | The /etc/gshadow- file is used to store backup information about groups that is critical to 282 | the security of those accounts, such as the hashed password and other security information. 283 | 284 | Rationale: 285 | 286 | It is critical to ensure that the /etc/gshadow- file is protected from unauthorized access. Although it 287 | is protected by default, the file permissions could be changed either inadvertently or through malicious 288 | actions. 289 | ' 290 | impact 1.0 291 | 292 | tag cis: 'distribution-independent-linux:6.1.9' 293 | tag level: 1 294 | 295 | describe file('/etc/gshadow-') do 296 | it { should exist } 297 | it { should_not be_more_permissive_than('0640') } 298 | it { should be_owned_by 'root' } 299 | its('gid') { should cmp expected_gid } 300 | end 301 | end 302 | 303 | control 'cis-dil-benchmark-6.1.10' do 304 | title 'Ensure no world writable files exist' 305 | desc ' 306 | Unix-based systems support variable settings to control access to files. World writable files are the 307 | least secure. See the chmod(2) man page for more information. 308 | 309 | Rationale: 310 | 311 | Data in world-writable files can be modified and compromised by any user on the system. World writable 312 | files may also indicate an incorrectly written script or program that could potentially be the cause of 313 | a larger compromise to the system\'s integrity. 314 | ' 315 | impact 1.0 316 | 317 | tag cis: 'distribution-independent-linux:6.1.10' 318 | tag level: 1 319 | 320 | describe command("df --local -P | awk '{ if (NR!=1) print $6 }' | xargs -I '{}' find '{}' -xdev -type f -perm -0002") do 321 | its('stdout') { should cmp '' } 322 | end 323 | end 324 | 325 | control 'cis-dil-benchmark-6.1.11' do 326 | title 'Ensure no unowned files or directories exist' 327 | desc ' 328 | Sometimes when administrators delete users from the password file they neglect to remove all files owned 329 | by those users from the system. 330 | 331 | Rationale: 332 | A new user who is assigned the deleted user\'s user ID or group ID may then end up "owning" these files, 333 | and thus have more access on the system than was intended. 334 | ' 335 | impact 1.0 336 | 337 | tag cis: 'distribution-independent-linux:6.1.11' 338 | tag level: 1 339 | 340 | describe command("df --local -P | awk '{ if (NR!=1) print $6 }' | xargs -I '{}' find '{}' -xdev -nouser") do 341 | its('stdout') { should cmp '' } 342 | end 343 | end 344 | 345 | control 'cis-dil-benchmark-6.1.12' do 346 | title 'Ensure no ungrouped files or directories exist' 347 | desc ' 348 | Sometimes when administrators delete users or groups from the system they neglect to remove all files 349 | owned by those users or groups. 350 | 351 | Rationale: A new user who is assigned the deleted user\'s user ID or group ID may then end up "owning" 352 | these files, and thus have more access on the system than was intended. 353 | ' 354 | impact 1.0 355 | 356 | tag cis: 'distribution-independent-linux:6.1.12' 357 | tag level: 1 358 | 359 | describe command("df --local -P | awk '{ if (NR!=1) print $6 }' | xargs -I '{}' find '{}' -xdev -nogroup") do 360 | its('stdout') { should cmp '' } 361 | end 362 | end 363 | 364 | control 'cis-dil-benchmark-6.1.13' do 365 | title 'Audit SUID executables' 366 | desc ' 367 | The owner of a file can set the file\'s permissions to run with the owner\'s or group\'s permissions, 368 | even if the user running the program is not the owner or a member of the group. The most common reason 369 | for a SUID program is to enable users to perform functions (such as changing their password) that require 370 | root privileges. 371 | 372 | Rationale: There are valid reasons for SUID programs, but it is important to identify and review such 373 | programs to ensure they are legitimate. 374 | ' 375 | impact 0.0 376 | 377 | tag cis: 'distribution-independent-linux:6.1.13' 378 | tag level: 1 379 | 380 | describe 'cis-dil-benchmark-6.1.13' do 381 | skip 'Not implemented' 382 | end 383 | end 384 | 385 | control 'cis-dil-benchmark-6.1.14' do 386 | title 'Audit SGID executables' 387 | desc ' 388 | The owner of a file can set the file\'s permissions to run with the owner\'s or group\'s permissions, 389 | even if the user running the program is not the owner or a member of the group. The most common 390 | reason for a SGID program is to enable users to perform functions (such as changing their password) 391 | that require root privileges. 392 | 393 | Rationale: 394 | There are valid reasons for SGID programs, but it is important to identify and review such programs to 395 | ensure they are legitimate. Review the files returned by the action in the audit section and check to see 396 | if system binaries have a different md5 checksum than what from the package. This is an indication that 397 | the binary may have been replaced. 398 | ' 399 | impact 0.0 400 | 401 | tag cis: 'distribution-independent-linux:6.1.14' 402 | tag level: 1 403 | 404 | describe 'cis-dil-benchmark-6.1.14' do 405 | skip 'Not implemented' 406 | end 407 | end 408 | -------------------------------------------------------------------------------- /controls/6_2_user_and_group_settings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Copyright:: 2017, Schuberg Philis B.V. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # author: Kristian Vlaardingerbroek 19 | 20 | title '6.2 User and Group Settings' 21 | 22 | uid_min = login_defs.UID_MIN.to_i 23 | 24 | shadow_files = ['/etc/shadow'] 25 | shadow_files << '/usr/share/baselayout/shadow' if file('/etc/nsswitch.conf').content =~ /^shadow:\s+(\S+\s+)*usrfiles/ 26 | 27 | passwd_files = ['/etc/passwd'] 28 | passwd_files << '/usr/share/baselayout/passwd' if file('/etc/nsswitch.conf').content =~ /^passwd:\s+(\S+\s+)*usrfiles/ 29 | 30 | group_files = ['/etc/group'] 31 | group_files << '/usr/share/baselayout/group' if file('/etc/nsswitch.conf').content =~ /^group:\s+(\S+\s+)*usrfiles/ 32 | 33 | control 'cis-dil-benchmark-6.2.1' do 34 | title 'Ensure password fields are not empty' 35 | desc ' 36 | An account with an empty password field means that anybody may log in as that user without providing a password. 37 | 38 | Rationale 39 | All accounts must have passwords or be locked to prevent the account from being used by an unauthorized user. 40 | ' 41 | impact 1.0 42 | 43 | tag cis: 'distribution-independent-linux:6.2.1' 44 | tag level: 1 45 | 46 | shadow_files.each do |f| 47 | describe shadow(f) do 48 | its('passwords') { should_not include '' } 49 | end 50 | end 51 | end 52 | 53 | control 'cis-dil-benchmark-6.2.2' do 54 | title 'Ensure no legacy "+" entries exist in /etc/passwd' 55 | desc ' 56 | The character + in various files used to be markers for systems to insert data from NIS maps at a certain point in a system configuration file. 57 | These entries are no longer required on most systems, but may exist in files that have been imported from other platforms. 58 | 59 | Rationale: 60 | These entries may provide an avenue for attackers to gain privileged access on the system. 61 | ' 62 | impact 1.0 63 | 64 | tag cis: 'distribution-independent-linux:6.2.2' 65 | tag level: 1 66 | 67 | passwd_files.each do |f| 68 | describe passwd(f) do 69 | its('users') { should_not include '+' } 70 | end 71 | end 72 | end 73 | 74 | control 'cis-dil-benchmark-6.2.3' do 75 | title 'Ensure no legacy "+" entries exist in /etc/shadow' 76 | desc ' 77 | The character + in various files used to be markers for systems to insert data from NIS maps at a certain point in a system 78 | configuration file. These entries are no longer required on most systems, but may exist in files that have been imported 79 | from other platforms. 80 | 81 | Rationale: These entries may provide an avenue for attackers to gain privileged access on the system. 82 | ' 83 | impact 1.0 84 | 85 | tag cis: 'distribution-independent-linux:6.2.3' 86 | tag level: 1 87 | 88 | shadow_files.each do |f| 89 | describe shadow(f) do 90 | its('users') { should_not include '+' } 91 | end 92 | end 93 | end 94 | 95 | control 'cis-dil-benchmark-6.2.4' do 96 | title 'Ensure no legacy "+" entries exist in /etc/group' 97 | desc ' 98 | The character + in various files used to be markers for systems to insert data from NIS maps at a certain point in a system 99 | configuration file. These entries are no longer required on most systems, but may exist in files that have been imported 100 | from other platforms. 101 | 102 | Rationale: These entries may provide an avenue for attackers to gain privileged access on the system. 103 | ' 104 | impact 1.0 105 | 106 | tag cis: 'distribution-independent-linux:6.2.4' 107 | tag level: 1 108 | 109 | group_files.each do |f| 110 | describe etc_group(f) do 111 | its('groups') { should_not include '+' } 112 | end 113 | end 114 | end 115 | 116 | control 'cis-dil-benchmark-6.2.5' do 117 | title 'Ensure root is the only UID 0 account' 118 | desc ' 119 | Any account with UID 0 has superuser privileges on the system. 120 | 121 | Rationale: This access must be limited to only the default root account and only from the system console. 122 | Administrative access must be through an unprivileged account using an approved mechanism as noted in 123 | Item 5.6 Ensure access to the su command is restricted. 124 | ' 125 | impact 1.0 126 | 127 | tag cis: 'distribution-independent-linux:6.2.5' 128 | tag level: 1 129 | 130 | passwd_files.each do |f| 131 | describe passwd(f).uids(0) do 132 | its('users') { should cmp ['root'] } 133 | end 134 | end 135 | end 136 | 137 | control 'cis-dil-benchmark-6.2.6' do 138 | title 'Ensure root PATH Integrity' 139 | desc ' 140 | The root user can execute any command on the system and could be fooled into executing programs unintentionally if 141 | the PATH is not set correctly. 142 | 143 | Rationale: Including the current working directory (.) or other writable directory in root\'s executable path makes it 144 | likely that an attacker can gain superuser access by forcing an administrator operating as root to execute 145 | a Trojan horse program. 146 | ' 147 | impact 1.0 148 | 149 | tag cis: 'distribution-independent-linux:6.2.6' 150 | tag level: 1 151 | 152 | root_path = os_env('PATH').split 153 | 154 | describe root_path do 155 | it { should_not be_empty } 156 | it { should_not include '' } 157 | it { should_not include '.' } 158 | end 159 | 160 | root_path.each do |entry| 161 | describe file(entry) do 162 | it { should be_directory } 163 | it { should_not be_writable.by 'group' } 164 | it { should_not be_writable.by 'other' } 165 | it { should be_owned_by 'root' } 166 | end 167 | end 168 | end 169 | 170 | control 'cis-dil-benchmark-6.2.7' do 171 | title 'Ensure all users\' home directories exist' 172 | desc ' 173 | Users can be defined in /etc/passwd without a home directory or with a home directory that does not actually exist. 174 | 175 | Rationale: If the user\'s home directory does not exist or is unassigned, the user will be placed in "/" and will not be 176 | able to write any files or have local environment variables set. 177 | ' 178 | impact 1.0 179 | 180 | tag cis: 'distribution-independent-linux:6.2.7' 181 | tag level: 1 182 | 183 | passwd_files.each do |f| 184 | passwd(f).where { uid.to_i >= uid_min }.where { shell !~ %r{^(/usr/sbin/nologin|/sbin/nologin|/bin/false)$} }.homes.each do |h| 185 | describe file(h) do 186 | it { should be_directory } 187 | end 188 | end 189 | end 190 | end 191 | 192 | control 'cis-dil-benchmark-6.2.8' do 193 | title 'Ensure users\' home directories permissions are 750 or more restrictive' 194 | desc ' 195 | While the system administrator can establish secure permissions for users\' home directories, the users can easily override these. 196 | 197 | Rationale: 198 | 199 | Group or world-writable user home directories may enable malicious users to steal or modify other users\' data or to gain 200 | another user\'s system privileges. 201 | ' 202 | impact 1.0 203 | 204 | tag cis: 'distribution-independent-linux:6.2.8' 205 | tag level: 1 206 | 207 | passwd_files.each do |f| 208 | passwd(f).where { uid.to_i >= uid_min }.where { shell !~ %r{^(/usr/sbin/nologin|/sbin/nologin|/bin/false)$} }.homes.each do |h| 209 | describe file(h) do 210 | it { should exist } 211 | it { should_not be_writable.by 'group' } 212 | it { should_not be_readable.by 'other' } 213 | it { should_not be_writable.by 'other' } 214 | it { should_not be_executable.by 'other' } 215 | end 216 | end 217 | end 218 | end 219 | 220 | control 'cis-dil-benchmark-6.2.9' do 221 | title 'Ensure users own their home directories' 222 | desc ' 223 | The user home directory is space defined for the particular user to set local environment variables and to store 224 | personal files. 225 | 226 | Rationale: 227 | 228 | Since the user is accountable for files stored in the user home directory, the user must be the owner of the directory. 229 | ' 230 | impact 1.0 231 | 232 | tag cis: 'distribution-independent-linux:6.2.9' 233 | tag level: 1 234 | 235 | passwd_files.each do |f| 236 | passwd(f).where { uid.to_i >= uid_min }.where { shell !~ %r{^(/usr/sbin/nologin|/sbin/nologin|/bin/false)$} }.entries.each do |entry| 237 | describe file(entry.home) do 238 | it { should be_owned_by entry.user } 239 | end 240 | end 241 | end 242 | end 243 | 244 | control 'cis-dil-benchmark-6.2.10' do 245 | title 'Ensure users\' dot files are not group or world writable' 246 | desc ' 247 | While the system administrator can establish secure permissions for users\' "dot" files, the users can easily override these. 248 | 249 | Rationale: 250 | Group or world-writable user configuration files may enable malicious users to steal or modify other users\' data or to gain another 251 | user\'s system privileges. 252 | ' 253 | impact 1.0 254 | 255 | tag cis: 'distribution-independent-linux:6.2.10' 256 | tag level: 1 257 | 258 | passwd_files.each do |pf| 259 | passwd(pf).where { uid.to_i >= uid_min }.where { shell !~ %r{^(/usr/sbin/nologin|/sbin/nologin|/bin/false)$} }.homes.each do |h| 260 | command("find #{h} -maxdepth 1 -type f -name '.*'").stdout.split.each do |f| 261 | describe file(f) do 262 | it { should_not be_writable.by 'group' } 263 | it { should_not be_writable.by 'other' } 264 | end 265 | end 266 | end 267 | end 268 | end 269 | 270 | control 'cis-dil-benchmark-6.2.11' do 271 | title 'Ensure no users have .forward files' 272 | desc ' 273 | The .forward file specifies an email address to forward the user\'s mail to. 274 | 275 | Rationale: 276 | 277 | Use of the .forward file poses a security risk in that sensitive data may be inadvertently transferred outside the organization. 278 | The .forward file also poses a risk as it can be used to execute commands that may perform unintended actions. 279 | ' 280 | impact 1.0 281 | 282 | tag cis: 'distribution-independent-linux:6.2.11' 283 | tag level: 1 284 | 285 | passwd_files.each do |f| 286 | passwd(f).homes.each do |home| 287 | describe file("#{home}/.forward") do 288 | it { should_not exist } 289 | end 290 | end 291 | end 292 | end 293 | 294 | control 'cis-dil-benchmark-6.2.12' do 295 | title 'Ensure no users have .netrc files' 296 | desc ' 297 | The .netrc file contains data for logging into a remote host for file transfers via FTP. 298 | 299 | Rationale: 300 | The .netrc file presents a significant security risk since it stores passwords in unencrypted form. Even if FTP is disabled, 301 | user accounts may have brought over .netrc files from other systems which could pose a risk to those systems. 302 | ' 303 | impact 1.0 304 | 305 | tag cis: 'distribution-independent-linux:6.2.12' 306 | tag level: 1 307 | 308 | passwd_files.each do |f| 309 | passwd(f).homes.each do |home| 310 | describe file("#{home}/.netrc") do 311 | it { should_not exist } 312 | end 313 | end 314 | end 315 | end 316 | 317 | control 'cis-dil-benchmark-6.2.13' do 318 | title 'Ensure users\' .netrc Files are not group or world accessible' 319 | desc ' 320 | While the system administrator can establish secure permissions for users\' .netrc files, the users can easily override these. 321 | 322 | Rationale: 323 | .netrc files may contain unencrypted passwords that may be used to attack other systems. 324 | ' 325 | impact 1.0 326 | 327 | tag cis: 'distribution-independent-linux:6.2.13' 328 | tag level: 1 329 | 330 | passwd_files.each do |f| 331 | passwd(f).homes.each do |home| 332 | next unless file("#{home}/.netrc").exist? 333 | 334 | it { should_not be_readable.by 'group' } 335 | it { should_not be_writable.by 'group' } 336 | it { should_not be_executable.by 'group' } 337 | it { should_not be_readable.by 'other' } 338 | it { should_not be_writable.by 'other' } 339 | it { should_not be_executable.by 'other' } 340 | end 341 | end 342 | end 343 | 344 | control 'cis-dil-benchmark-6.2.14' do 345 | title 'Ensure no users have .rhosts files' 346 | desc ' 347 | While no .rhosts files are shipped by default, users can easily create them. 348 | 349 | Rationale: 350 | This action is only meaningful if .rhosts support is permitted in the file /etc/pam.conf. Even though the .rhosts files are 351 | ineffective if support is disabled in /etc/pam.conf, they may have been brought over from other systems and could contain 352 | information useful to an attacker for those other systems. 353 | ' 354 | impact 1.0 355 | 356 | tag cis: 'distribution-independent-linux:6.2.14' 357 | tag level: 1 358 | 359 | passwd_files.each do |f| 360 | passwd(f).homes.each do |home| 361 | describe file("#{home}/.rhosts") do 362 | it { should_not exist } 363 | end 364 | end 365 | end 366 | end 367 | 368 | control 'cis-dil-benchmark-6.2.15' do 369 | title 'Ensure all groups in /etc/passwd exist in /etc/group' 370 | desc ' 371 | Over time, system administration errors and changes can lead to groups being defined in /etc/passwd but not 372 | in /etc/group. 373 | 374 | Rationale: Groups defined in the /etc/passwd file but not in the /etc/group file pose a threat to system security 375 | since group permissions are not properly managed. 376 | ' 377 | impact 1.0 378 | 379 | tag cis: 'distribution-independent-linux:6.2.15' 380 | tag level: 1 381 | 382 | passwd_files.each do |f| 383 | passwd(f).gids.map(&:to_i).each do |gid| 384 | describe.one do 385 | group_files.each do |gf| 386 | describe etc_group(gf) do 387 | its(:gids) { should include gid } 388 | end 389 | end 390 | end 391 | end 392 | end 393 | end 394 | 395 | control 'cis-dil-benchmark-6.2.16' do 396 | title 'Ensure no duplicate UIDs exist' 397 | desc ' 398 | Although the useradd program will not let you create a duplicate User ID (UID), it is possible for an administrator 399 | to manually edit the /etc/passwd file and change the UID field. 400 | 401 | Rationale: 402 | Users must be assigned unique UIDs for accountability and to ensure appropriate access protections. 403 | ' 404 | impact 1.0 405 | 406 | tag cis: 'distribution-independent-linux:6.2.16' 407 | tag level: 1 408 | 409 | passwd_files.each do |f| 410 | describe passwd(f).uids.detect { |e| passwd(f).uids.count(e) > 1 } do 411 | it { should be_nil } 412 | end 413 | end 414 | end 415 | 416 | control 'cis-dil-benchmark-6.2.17' do 417 | title 'Ensure no duplicate GIDs exist' 418 | desc ' 419 | Although the groupadd program will not let you create a duplicate Group ID (GID), it is possible for an administrator to 420 | manually edit the /etc/group file and change the GID field. 421 | 422 | Rationale: 423 | User groups must be assigned unique GIDs for accountability and to ensure appropriate access protections. 424 | ' 425 | impact 1.0 426 | 427 | tag cis: 'distribution-independent-linux:6.2.17' 428 | tag level: 1 429 | 430 | group_files.each do |f| 431 | describe etc_group(f).gids.detect { |e| etc_group(f).gids.count(e) > 1 } do 432 | it { should be_nil } 433 | end 434 | end 435 | end 436 | 437 | control 'cis-dil-benchmark-6.2.18' do 438 | title 'Ensure no duplicate user names exist' 439 | desc ' 440 | Although the useradd program will not let you create a duplicate user name, it is possible for an administrator to manually 441 | edit the /etc/passwd file and change the user name. 442 | 443 | Rationale: 444 | If a user is assigned a duplicate user name, it will create and have access to files with the first UID for that username in /etc/passwd. 445 | For example, if "test4" has a UID of 1000 and a subsequent "test4" entry has a UID of 2000, logging in as "test4" will use UID 1000. 446 | Effectively, the UID is shared, which is a security problem. 447 | ' 448 | impact 1.0 449 | 450 | tag cis: 'distribution-independent-linux:6.2.18' 451 | tag level: 1 452 | 453 | passwd_files.each do |f| 454 | describe passwd(f).users.detect { |e| passwd(f).users.count(e) > 1 } do 455 | it { should be_nil } 456 | end 457 | end 458 | end 459 | 460 | control 'cis-dil-benchmark-6.2.19' do 461 | title 'Ensure no duplicate group names exist' 462 | desc ' 463 | Although the groupadd program will not let you create a duplicate group name, it is possible for an administrator to manually edit the /etc/group 464 | file and change the group name. 465 | 466 | Rationale: 467 | If a group is assigned a duplicate group name, it will create and have access to files with the first GID for that group in /etc/group. 468 | Effectively, the GID is shared, which is a security problem. 469 | ' 470 | impact 1.0 471 | 472 | tag cis: 'distribution-independent-linux:6.2.19' 473 | tag level: 1 474 | 475 | group_files.each do |f| 476 | describe etc_group(f).groups.detect { |e| etc_group(f).groups.count(e) > 1 } do 477 | it { should be_nil } 478 | end 479 | end 480 | end 481 | 482 | control 'cis-dil-benchmark-6.2.20' do 483 | title 'Ensure shadow group is empty' 484 | desc ' 485 | The shadow group allows system programs which require access the ability to read the /etc/shadow file. No users should be assigned 486 | to the shadow group. 487 | 488 | Rationale: 489 | Any users assigned to the shadow group would be granted read access to the /etc/shadow file. If attackers can gain read access 490 | to the /etc/shadow file, they can easily run a password cracking program against the hashed passwords to break them. Other security 491 | information that is stored in the /etc/shadow file (such as expiration) could also be useful to subvert additional user accounts. 492 | ' 493 | impact 1.0 494 | 495 | tag cis: 'distribution-independent-linux:6.2.20' 496 | tag level: 1 497 | 498 | group_files.each do |f| 499 | describe etc_group(f).where(name: 'shadow') do 500 | its(:users) { should be_empty } 501 | end 502 | end 503 | end 504 | -------------------------------------------------------------------------------- /inspec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: cis-dil-benchmark 3 | title: CIS Distribution Independent Linux Benchmark Profile 4 | maintainer: Kristian Vlaardingerbroek 5 | copyright: Schuberg Philis B.V. 6 | copyright_email: kvlaardingerbroek@schubergphilis.com 7 | license: Apache-2.0 8 | summary: An InSpec Compliance profile for the CIS Distribution Independent Linux Benchmark 9 | version: 0.4.13 10 | inspec_version: '>= 4.6.3' 11 | supports: 12 | - platform-family: linux 13 | inputs: 14 | - name: cis_level 15 | required: false 16 | description: 'CIS profile level to audit' 17 | value: 2 18 | type: numeric 19 | -------------------------------------------------------------------------------- /libraries/grubconf.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | class GrubConf < Inspec.resource(1) 4 | name 'grub_conf' 5 | 6 | def locations 7 | %w(/boot/grub/grub.conf /boot/grub/grub.cfg /boot/grub/menu.lst /boot/boot/grub/grub.conf /boot/boot/grub/grub.cfg /boot/boot/grub/menu.lst /boot/grub2/grub.cfg) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | ":gitSignOff" 6 | ], 7 | "dependencyDashboard": true, 8 | "dependencyDashboardAutoclose": true, 9 | "packageRules": [ 10 | { 11 | "matchUpdateTypes": ["patch", "minor"], 12 | "automerge": true 13 | } 14 | ] 15 | } 16 | --------------------------------------------------------------------------------