Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
jajera authored Dec 2, 2020
1 parent 0796657 commit 7a051f4
Show file tree
Hide file tree
Showing 8 changed files with 12,832 additions and 0 deletions.
5,703 changes: 5,703 additions & 0 deletions controls/translated-controls_l1.rb

Large diffs are not rendered by default.

6,812 changes: 6,812 additions & 0 deletions controls/translated-controls_l2.rb

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions inspec.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
lockfile_version: 1
depends: []
11 changes: 11 additions & 0 deletions inspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: cis-windows10-1511-level1
title: CIS Microsoft Windows 10 (1511) Benchmark Level 1
summary: CIS Microsoft Windows 10 (1511) Benchmark Level 1 translated from SCAP
version: 1.1.0-6
maintainer: Chef Software, Inc.
copyright: Chef Software, Inc.
copyright_email: [email protected]
license: Proprietary, All rights reserved
supports:
- platform-family: windows
61 changes: 61 additions & 0 deletions libraries/Plist.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class Plist < Inspec.resource(1)
name 'plist'
supports platform: 'darwin'
desc 'plist files (also known as property files) store data, often user and system settings. The files may be text or binary.'
example "
describe plist('/System/Library/CoreServices/SystemVersion.plist') do
it { should exist }
its('ProductName') { should eq 'Mac OS X' }
end
"

def initialize(path, opts = {})
@path = path
@xpath = opts[:xpath]
@json_data = nil
@xml_data = nil
end

def to_s
"plist #{@path}" + (@xpath ? " with xpath: #{@xpath}" : '')
end

def exists?
if @path =~ /\$HOME/
expand_home = inspec.command('echo $HOME').stdout.strip
return inspec.file(@path.gsub('$HOME', expand_home)).exist?
end
inspec.file(@path).exist?
end

def method_missing(*args)
load_json
required_key = args[0].is_a?(Array) ? args[0].map { |x| x.to_s } : args[0].to_s
@json_data.dig(*required_key)
end

def xpath_value
raise Inspec::Exceptions::ResourceFailed ':xpath must be specified in options hash to use xpath_value' unless @xpath
load_xml
result = @xml_data.xpath(@xpath)
result.respond_to?(:text) ? result.text : result
end

private

def load_json
begin
@json_data ||= JSON.parse(inspec.command("plutil -convert json -o - #{@path}").stdout)
rescue => e
raise Inspec::Exceptions::ResourceFailed, "Failed to read plist data for '#{@path}': #{e.message}"
end
end

def load_xml
begin
@xml_data ||= Nokogiri::XML.parse(inspec.command("plutil -convert xml1 -o - #{@path}").stdout)
rescue => e
raise Inspec::Exceptions::ResourceFailed, "Failed to read plist data for '#{@path}': #{e.message}"
end
end
end
118 changes: 118 additions & 0 deletions libraries/RegistrySecurityDescriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
class RegistrySecurityDescriptor < Inspec.resource(1)
name 'registry_security_descriptor'
supports platform: 'windows'
desc 'Represents the security descriptor for a registry key in Windows'
example "
# return all user rights associated with registry key
registry_rights = registry_security_descriptor('HKLM:\\System\\CurrentControlSet\\Control\\SecurePipeServers\\Winreg')
permitted_sids = ['S-1-5-32-551', 'S-1-5-19']
permitted_sids.each do |trustee|
describe registry_rights.permissions[trustee] do
its(['Delete']) { should cmp 0 }
its(['ReadControl']) { should cmp 0 }
end
end
# return all user rights associated with registry key and verify if trustee sid(s) exist
registry_rights = registry_security_descriptor('HKLM:\\System\\CurrentControlSet\\Control\\SecurePipeServers\\Winreg')
describe registry_rights do
its('permissions') { should include('S-1-5-32-551', 'S-1-5-19') }
end
# return a specific users' rights associated with a registry key
describe registry_security_descriptor('HKLM:\\System\\CurrentControlSet\\Control\\SecurePipeServers\\Winreg').permissions_for_trustee('S-1-5-19') do
# Assert the permission associated with the specified registry key
its(['ReadControl']) { should cmp '0' }
end
# return a list of user sid's who have rights associated with a registry key
describe registry_security_descriptor('HKLM:\\System\\CurrentControlSet\\Control\\SecurePipeServers\\Winreg') do
# Assert the permission associated with the specified registry key
its ('trustees_with_any_permission') { should include 'S-1-5-32-546' }
end
"

ACCESS_RIGHTS_BINARY = {
'Delete' => 0b10000000000000000,
'ReadControl' => 0b100000000000000000,
'WriteDac' => 0b1000000000000000000,
'WriteOwner' => 0b10000000000000000000,
'AccessSystemSecurity' => 0b1000000000000000000000000,
'Synchronize' => 0b100000000000000000000,
'KeyAllAccess' => 0b11110000000000111111,
'KeyCreateLink' => 0b100000,
'KeyCreateSubKey' => 0b100,
'KeyEnumerateSubKeys' => 0b1000,
'KeyExecute' => 0b100000000000011001,
'KeyNotify' => 0b10000,
'KeyQueryValue' => 0b1,
'KeyRead' => 0b100000000000011001,
'KeySetValue' => 0b10,
'KeyWow6432Key' => 0b1000000000,
'KeyWow6464Key' => 0b100000000,
'KeyWow64Res' => 0b1100000000,
'KeyWrite' => 0b00000000000000110
}.freeze

def initialize(path, options = {})
@path = path
@trustee_access_mask = nil
end

def permissions
fetch_results
return nil unless @trustee_access_mask
results = {}
@trustee_access_mask.each do |trusteesid, accessmask|
accessrights = {}
ACCESS_RIGHTS_BINARY.each do |k,v|
if accessmask.to_i & v == 0
accessrights[k] = 0
else
accessrights[k] = 1
end
end
results[trusteesid] = accessrights
end
results
end

def permissions_for_trustee(trustee)
fetch_results
return nil unless @trustee_access_mask || trustee
results = {}
accessmask = @trustee_access_mask[trustee]
ACCESS_RIGHTS_BINARY.each do |k,v|
results[k] = (accessmask.to_i & v == 0) ? 0 : 1
end
results
end

def trustees_with_any_permission
fetch_results
return [] unless @trustee_access_mask
trustees = []
@trustee_access_mask.each do |trusteesid, accessmask|
trustees.push(trusteesid)
end
trustees
end

private
def fetch_results
return if @trustee_access_mask
sddl = inspec.powershell("(Get-Acl #{@path}).SDDL").stdout.strip.gsub("\r\n","")
raise "The provided Registry Key '#{@path}' does not have an SDDL associated." if sddl == ""
@trustee_access_mask = {}
access_details = inspec.powershell("(Invoke-CimMethod Win32_SecurityDescriptorHelper -MethodName SDDLToWin32SD -Arguments @{ SDDL = '#{sddl}' }).Descriptor.DACL | Select @{Name=\"SID\";Expression={$_.Trustee.SIDString}},AccessMask").stdout.strip.split("\r\n")[2..-1].map { |entry| entry.split }
access_details.each do |access_detail|
trusteesid = access_detail[0]
accessmask = access_detail[1]
if @trustee_access_mask.key?(trusteesid) && @trustee_access_mask[trusteesid]
@trustee_access_mask[trusteesid] = (accessmask.to_i + @trustee_access_mask[trusteesid].to_i).to_s
else
@trustee_access_mask[trusteesid] = accessmask
end
end
end
end
65 changes: 65 additions & 0 deletions libraries/SecurityDescriptor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
class SecurityDescriptor < Inspec.resource(1)
name 'security_descriptor'
supports supports platform: 'windows'
desc 'Represents the security descriptor for a file in Windows'
example "
describe security_descriptor('C:\\windows\\system32\\EventVwr.exe') do
# Assert the set of entities with a given permission
its('ReadAndExecute') { should_not include 'S-1-5-32-546' }
# Assert the permissions for a given entity
its('S-1-5-32-544') { should_not include 'Write' }
end
"

def initialize(filename, options = {})
@filename = filename
@results = nil
end

%w{Read ReadAndExecute Write Modify Sychronize FullControl}.each do |perm|
define_method perm do
fetch_results unless @results
# Return keys that have this permission, with the domain stripped
@results.select { |k,v| v.include?(perm) }.keys.map { |key| key.split("\\")[-1] }
end
end

def method_missing(name)
fetch_results unless @results
# Return the results for this entity if it exists (with some domain name) in the result set
entity_key = @results.keys.select { |key| key.split("\\")[-1] == name.to_s }[0]
return @results[entity_key] if entity_key
# Entity not in the result set is "no permissions"
[]
end

def to_s
"Security Descriptor for #{@filename}"
end

private

def fetch_results
@results = {}
cmd = inspec.powershell("Get-Acl #{@filename} | select -expand access")
raise cmd.stderr.strip unless cmd.stderr == ''
access_details = cmd.stdout.strip.split("\r\n\r\n").map { |entry| entry.split("\r\n") }
access_details.each do |access_detail|
entity = access_detail.select { |a| a =~ %r{^IdentityReference} }[0].tr(' ', '').split(':')[-1]
permissions = access_detail.select { |a| a =~ %r{^FileSystemRights} }[0].tr(' ', '').split(':')[-1].split(',')
# Get-Acl displays entity names in its results rather than SIDs.
# It is preferable to work with SIDs when testing security
# Replace the entity name from Get-Acl with a SID where possible.
entity_id = get_sid(entity.split("\\")[-1])
@results[entity_id] = permissions
end
end

def get_sid(entity_name)
group_sids = inspec.command("wmic group where 'Name=\"#{entity_name}\"' get Name\",\"SID /format:csv").stdout.strip.split("\r\n\r\n")[1..-1].map { |entry| entry.split(',') }
return group_sids[0][2] unless group_sids.empty?
user_sids = inspec.command("wmic useraccount where 'Name=\"#{entity_name}\"' get Name\",\"SID /format:csv").stdout.strip.split("\r\n\r\n")[1..-1].map { |entry| entry.split(',') }
return user_sids[0][2] unless user_sids.empty?
entity_name
end
end
59 changes: 59 additions & 0 deletions libraries/SecurityIdentifier.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
class SecurityIdentifier < Inspec.resource(1)
name 'security_identifier'
supports platform: 'windows'
desc 'Resource that returns a Security Identifier for a given entity name in Windows. Because different entities can have the same name (e.g. a user and group can both be called \'devops\') the resource requires the type of the entity (:user, :group) to be stated to avoid an ambiguous test. If the entity type is unknown (e.g. when working with SCAP content that names an entity but does not declare its type) you may give the type as :unspecified to explicitly state that you need the resource to try to determine a SID when the entity type is not known.'
example "
describe security_policy do
its(\"SeRemoteInteractiveLogonRight\") { should_not include security_identifier(group: 'Guests') }
end
"

def initialize(opts = {})
supported_opt_keys = [:user, :group, :unspecified]
raise "Invalid security_identifier param '#{opts}'. Please pass a hash with these supported keys: #{supported_opt_keys}" unless opts.respond_to?(:keys)
raise "Unsupported security_identifier options '#{opts.keys - supported_opt_keys}'. Supported keys: #[supported_opt_keys]" unless (opts.keys - supported_opt_keys).empty?
raise 'Specifying more than one of :user :group or :unspecified for security_identifier is not supported' unless opts.keys and (opts.keys & supported_opt_keys).length == 1
if opts[:user]
@type = :user
@name = opts[:user]
end
if opts[:group]
@type = :group
@name = opts[:group]
end
if opts[:unspecified]
@type = :unspecified
@name = opts[:unspecified]
end
raise 'Specify one of :user :group or :unspecified for security_identifier' unless @name
@sids = nil
end

def sid
fetch_sids unless @sids
@sids[@name] || @name
end

def fetch_sids
@sids = {}
case @type
when :group
sid_data = wmi_results_array("wmic group where 'Name=\"#{@name}\"' get Name\",\"SID /format:csv")
when :user
sid_data = wmi_results_array("wmic useraccount where 'Name=\"#{@name}\"' get Name\",\"SID /format:csv")
when :unspecified
# try group first, then user
sid_data = wmi_results_array("wmic group where 'Name=\"#{@name}\"' get Name\",\"SID /format:csv")
if sid_data.empty?
sid_data = wmi_results_array("wmic useraccount where 'Name=\"#{@name}\"' get Name\",\"SID /format:csv")
end
else
raise "Unhandled entity type '#{@type}'"
end
sid_data.each { |sid| @sids[sid[1]] = sid[2] }
end

def wmi_results_array(query)
inspec.command(query).stdout.strip.split("\r\n\r\n")[1..-1].map { |entry| entry.split(',') }
end
end

0 comments on commit 7a051f4

Please sign in to comment.