ardecy 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.md +6 -2
- data/lib/ardecy.rb +5 -4
- data/lib/ardecy/harden.rb +55 -59
- data/lib/ardecy/harden/cmdline.rb +222 -0
- data/lib/ardecy/harden/modules.rb +290 -0
- data/lib/ardecy/harden/mountpoint.rb +149 -0
- data/lib/ardecy/harden/perms.rb +110 -0
- data/lib/ardecy/harden/sysctl.rb +7 -5
- data/lib/ardecy/harden/sysctl/kernel.rb +67 -58
- data/lib/ardecy/harden/sysctl/network.rb +52 -66
- data/lib/ardecy/options.rb +12 -0
- data/lib/ardecy/privacy.rb +2 -0
- data/lib/ardecy/version.rb +1 -1
- data/lib/display.rb +13 -3
- data/lib/nito.rb +30 -0
- metadata +7 -2
- metadata.gz.sig +0 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'display'
|
4
|
+
require 'nito'
|
5
|
+
|
6
|
+
module Ardecy
|
7
|
+
module Harden
|
8
|
+
module Mountpoint
|
9
|
+
def self.exec(args)
|
10
|
+
ProcHidepid.new(args).x
|
11
|
+
puts " ===> Mountpoint Corrected." if args[:fix]
|
12
|
+
end
|
13
|
+
|
14
|
+
class MountInc
|
15
|
+
include Display
|
16
|
+
include NiTo
|
17
|
+
|
18
|
+
def initialize(args)
|
19
|
+
@res = 'FAIL'
|
20
|
+
@args = args
|
21
|
+
@tab = 2
|
22
|
+
end
|
23
|
+
|
24
|
+
def x
|
25
|
+
scan
|
26
|
+
add_group
|
27
|
+
build_args
|
28
|
+
fix
|
29
|
+
systemd_case
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_group
|
33
|
+
return unless @args[:fix] && @group
|
34
|
+
|
35
|
+
has_group = group_search
|
36
|
+
unless has_group
|
37
|
+
if File.exists? '/usr/sbin/groupadd'
|
38
|
+
puts " => Group #{@group} added." if system("/usr/sbin/groupadd #{@group}")
|
39
|
+
elsif File.exists? '/usr/bin/groupadd'
|
40
|
+
puts " => Group #{@group} added." if system("/usr/bin/groupadd #{@group}")
|
41
|
+
else
|
42
|
+
puts '[-] Can\'t find command groupadd'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def group_search
|
48
|
+
if File.readable? '/etc/group'
|
49
|
+
etc_group = File.readlines('/etc/group')
|
50
|
+
etc_group.each { |l| return true if l =~ /#{@group}/ }
|
51
|
+
else
|
52
|
+
puts " [-] /etc/group is not readable"
|
53
|
+
end
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
def scan
|
58
|
+
return unless mount_match('/proc/mounts')
|
59
|
+
|
60
|
+
print " - Checking #{@name} contain " + @ensure.join(',') if @args[:audit]
|
61
|
+
res_a = []
|
62
|
+
@ensure.each do |v|
|
63
|
+
o = v.split('=')
|
64
|
+
res_a << true if @val =~ /#{o[0]}=[a-z0-9]+/
|
65
|
+
end
|
66
|
+
@res = 'OK' if res_a.length == @ensure.length
|
67
|
+
|
68
|
+
@tab ? result(@res, @tab) : result(@res) if @args[:audit]
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_args
|
72
|
+
return unless @args[:fix]
|
73
|
+
return if @res =~ /OK/
|
74
|
+
|
75
|
+
v = @val.split ' '
|
76
|
+
@ensure.each do |e|
|
77
|
+
o = e.split('=')
|
78
|
+
v[3] += ",#{e}" unless v[3] =~ /#{o[0]}=[a-z0-9]+/
|
79
|
+
end
|
80
|
+
@new = v.join(' ')
|
81
|
+
end
|
82
|
+
|
83
|
+
def fix
|
84
|
+
return unless @args[:fix]
|
85
|
+
return if @res =~ /OK/
|
86
|
+
|
87
|
+
if mount_match('/etc/fstab')
|
88
|
+
edit_fstab
|
89
|
+
else
|
90
|
+
File.write('/etc/fstab', "\n#{@new}\n", mode: 'a')
|
91
|
+
end
|
92
|
+
|
93
|
+
puts "old -> " + @val
|
94
|
+
puts "new -> " + @new
|
95
|
+
puts
|
96
|
+
end
|
97
|
+
|
98
|
+
def mount_match(file)
|
99
|
+
File.readlines(file).each do |l|
|
100
|
+
if l =~ /^#{@name}/
|
101
|
+
@val = l
|
102
|
+
return true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
false
|
106
|
+
end
|
107
|
+
|
108
|
+
def edit_fstab
|
109
|
+
sed(/^#{@name}/, @new, '/etc/fstab')
|
110
|
+
end
|
111
|
+
|
112
|
+
def systemd_case
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class ProcHidepid < Mountpoint::MountInc
|
117
|
+
def initialize(args)
|
118
|
+
super
|
119
|
+
@name = 'proc'
|
120
|
+
@ensure = [ 'hidepid=2', 'gid=proc' ]
|
121
|
+
@group = 'proc'
|
122
|
+
end
|
123
|
+
|
124
|
+
# man logind.conf check under:
|
125
|
+
# > /etc/systemd/logind.conf.d/*.conf
|
126
|
+
# > /run/systemd/logind.conf.d/*.conf
|
127
|
+
# > /usr/lib/systemd/logind.conf.d/*.conf
|
128
|
+
def systemd_case
|
129
|
+
return unless @args[:fix]
|
130
|
+
|
131
|
+
if File.exist? '/etc/systemd/logind.conf'
|
132
|
+
create_content '/etc/systemd/logind.conf.d'
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def create_content(in_dir)
|
137
|
+
content = [
|
138
|
+
'[Service]',
|
139
|
+
'SupplementaryGroups=proc',
|
140
|
+
''
|
141
|
+
]
|
142
|
+
Dir.mkdir in_dir, 0700 unless Dir.exists? in_dir
|
143
|
+
File.write("#{in_dir}/hidepid.conf", content.join("\n"), mode: 'w')
|
144
|
+
puts " > Creating file #{in_dir}/hidepid.conf"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'display'
|
4
|
+
|
5
|
+
module Ardecy
|
6
|
+
module Harden
|
7
|
+
module Perms
|
8
|
+
class DirCheck
|
9
|
+
include Display
|
10
|
+
|
11
|
+
def initialize(args)
|
12
|
+
@args = args
|
13
|
+
@res = 'OK'
|
14
|
+
@exp = 0755
|
15
|
+
@tab = 2
|
16
|
+
end
|
17
|
+
|
18
|
+
def x
|
19
|
+
scan
|
20
|
+
fix
|
21
|
+
end
|
22
|
+
|
23
|
+
def scan
|
24
|
+
return unless Dir.exist? @name
|
25
|
+
|
26
|
+
perm = File.stat(@name).mode & 07777
|
27
|
+
@line = "Permission on #{@name}"
|
28
|
+
|
29
|
+
perm_show(@line, @exp) if @args[:audit]
|
30
|
+
@res = 'FAIL' if perm > @exp
|
31
|
+
@tab ? result(@res, @tab) : result(@res) if @args[:audit]
|
32
|
+
end
|
33
|
+
|
34
|
+
def fix
|
35
|
+
return unless @args[:fix]
|
36
|
+
|
37
|
+
File.chmod @exp, @name unless @res =~ /OK/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Directory
|
42
|
+
def self.exec(args)
|
43
|
+
Directory::Home.new(args).x
|
44
|
+
Directory::CronDaily.new(args).x
|
45
|
+
Directory::Boot.new(args).x
|
46
|
+
Directory::UsrSrc.new(args).x
|
47
|
+
Directory::LibMod.new(args).x
|
48
|
+
Directory::UsrLibMod.new(args).x
|
49
|
+
puts " ===> Permission Corrected." if args[:fix]
|
50
|
+
end
|
51
|
+
|
52
|
+
class Home < Perms::DirCheck
|
53
|
+
def initialize(args)
|
54
|
+
super
|
55
|
+
@exp = 0700
|
56
|
+
end
|
57
|
+
|
58
|
+
def x
|
59
|
+
Dir.glob('/home/*').each { |d|
|
60
|
+
@name = d
|
61
|
+
scan
|
62
|
+
fix
|
63
|
+
}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class CronDaily < Perms::DirCheck
|
68
|
+
def initialize(args)
|
69
|
+
super
|
70
|
+
@name = '/etc/cron.daily'
|
71
|
+
@exp = 0700
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class Boot < Perms::DirCheck
|
76
|
+
def initialize(args)
|
77
|
+
super
|
78
|
+
@name = '/boot'
|
79
|
+
@exp = 0700
|
80
|
+
@tab = 3
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class UsrSrc < Perms::DirCheck
|
85
|
+
def initialize(args)
|
86
|
+
super
|
87
|
+
@name = '/usr/src'
|
88
|
+
@exp = 0700
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class LibMod < Perms::DirCheck
|
93
|
+
def initialize(args)
|
94
|
+
super
|
95
|
+
@name = '/lib/modules'
|
96
|
+
@exp = 0700
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
class UsrLibMod < Perms::DirCheck
|
101
|
+
def initialize(args)
|
102
|
+
super
|
103
|
+
@name = '/usr/lib/modules'
|
104
|
+
@exp = 0700
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/ardecy/harden/sysctl.rb
CHANGED
@@ -11,6 +11,12 @@ module Ardecy
|
|
11
11
|
class SysKern
|
12
12
|
include Display
|
13
13
|
|
14
|
+
def initialize(args)
|
15
|
+
@res = 'FALSE'
|
16
|
+
@args = args
|
17
|
+
@exp = '0'
|
18
|
+
end
|
19
|
+
|
14
20
|
def scan
|
15
21
|
kernel_show(@line, @exp) if @args[:audit]
|
16
22
|
if File.exist? @file
|
@@ -23,11 +29,7 @@ module Ardecy
|
|
23
29
|
else
|
24
30
|
@res = 'NO FOUND'
|
25
31
|
end
|
26
|
-
if @
|
27
|
-
kernel_res(@res, @tab) if @args[:audit]
|
28
|
-
elsif @args[:audit]
|
29
|
-
kernel_res(@res)
|
30
|
-
end
|
32
|
+
@tab ? result(@res, @tab) : result(@res) if @args[:audit]
|
31
33
|
end
|
32
34
|
|
33
35
|
def fix
|
@@ -4,205 +4,214 @@ module Ardecy
|
|
4
4
|
module Harden
|
5
5
|
module Sysctl
|
6
6
|
module Kernel
|
7
|
+
def self.exec(args)
|
8
|
+
Kernel::KPointer.new(args).x
|
9
|
+
Kernel::Dmesg.new(args).x
|
10
|
+
Kernel::Printk.new(args).x
|
11
|
+
Kernel::BpfDisabled.new(args).x
|
12
|
+
Kernel::BpfJitHarden.new(args).x
|
13
|
+
Kernel::LdiskAutoload.new(args).x
|
14
|
+
Kernel::UserFaultFd.new(args).x
|
15
|
+
Kernel::KExecLoadDisabled.new(args).x
|
16
|
+
Kernel::SysRQ.new(args).x
|
17
|
+
Kernel::UsernsClone.new(args).x
|
18
|
+
Kernel::MaxUserNameSpace.new(args).x
|
19
|
+
Kernel::PerfEventParanoid.new(args).x
|
20
|
+
Kernel::YamaPtrace.new(args).x
|
21
|
+
Kernel::VmMmapRndBits.new(args).x
|
22
|
+
Kernel::VmMmapRndCompatBits.new(args).x
|
23
|
+
Kernel::FsProtectedSymlinks.new(args).x
|
24
|
+
Kernel::FsProtectedHardlinks.new(args).x
|
25
|
+
Kernel::FsProtectedFifos.new(args).x
|
26
|
+
Kernel::FsProtectedRegular.new(args).x
|
27
|
+
Kernel::FsSuidDumpable.new(args).x
|
28
|
+
end
|
29
|
+
|
7
30
|
class KPointer < Sysctl::SysKern
|
8
31
|
def initialize(args)
|
9
32
|
@file = '/proc/sys/kernel/kptr_restrict'
|
10
|
-
@exp = '2'
|
11
|
-
@res = 'FALSE'
|
12
33
|
@line = 'kernel.kptr_restrict'
|
13
|
-
|
34
|
+
super
|
35
|
+
@exp = '2'
|
14
36
|
end
|
15
37
|
end
|
16
38
|
|
17
39
|
class Dmesg < Sysctl::SysKern
|
18
40
|
def initialize(args)
|
19
41
|
@file = '/proc/sys/kernel/dmesg_restrict'
|
20
|
-
@exp = '1'
|
21
|
-
@res = 'FALSE'
|
22
42
|
@line = 'kernel.dmesg_restrict'
|
23
|
-
|
43
|
+
super
|
44
|
+
@exp = '1'
|
24
45
|
end
|
25
46
|
end
|
26
47
|
|
27
48
|
class Printk < Sysctl::SysKern
|
28
49
|
def initialize(args)
|
29
50
|
@file = '/proc/sys/kernel/printk'
|
30
|
-
@exp = '3 3 3 3'
|
31
|
-
@res = 'FALSE'
|
32
51
|
@line = 'kernel.printk'
|
33
|
-
@
|
52
|
+
@tab = 6
|
53
|
+
super
|
54
|
+
@exp = '3 3 3 3'
|
34
55
|
end
|
35
56
|
|
36
57
|
def scan
|
37
58
|
kernel_show(@line, @exp) if @args[:audit]
|
38
59
|
value = File.read(@file).chomp
|
39
60
|
@res = 'OK' if value =~ /3\s+3\s+3\s+3/
|
40
|
-
|
61
|
+
result(@res) if @args[:audit]
|
41
62
|
end
|
42
63
|
end
|
43
64
|
|
44
65
|
class BpfDisabled < Sysctl::SysKern
|
45
66
|
def initialize(args)
|
46
67
|
@file = '/proc/sys/kernel/unprivileged_bpf_disabled'
|
47
|
-
@exp = '1'
|
48
|
-
@res = 'FALSE'
|
49
68
|
@line = 'kernel.unprivileged_bpf_disabled'
|
50
69
|
@tab = 2
|
51
|
-
|
70
|
+
super
|
71
|
+
@exp = '1'
|
52
72
|
end
|
53
73
|
end
|
54
74
|
|
55
75
|
class BpfJitHarden < Sysctl::SysKern
|
56
76
|
def initialize(args)
|
57
77
|
@file = '/proc/sys/net/core/bpf_jit_harden'
|
58
|
-
@exp = '2'
|
59
|
-
@res = 'FALSE'
|
60
78
|
@line = 'net.core.bpf_jit_harden'
|
61
|
-
|
79
|
+
super
|
80
|
+
@exp = '2'
|
62
81
|
end
|
63
82
|
end
|
64
83
|
|
65
84
|
class LdiskAutoload < Sysctl::SysKern
|
66
85
|
def initialize(args)
|
67
86
|
@file = '/proc/sys/dev/tty/ldisc_autoload'
|
68
|
-
@exp = '0'
|
69
|
-
@res = 'FALSE'
|
70
87
|
@line = 'dev.tty.ldisc_autoload'
|
71
|
-
|
88
|
+
super
|
72
89
|
end
|
73
90
|
end
|
74
91
|
|
75
92
|
class UserFaultFd < Sysctl::SysKern
|
76
93
|
def initialize(args)
|
77
94
|
@file = '/proc/sys/vm/unprivileged_userfaultfd'
|
78
|
-
@exp = '0'
|
79
|
-
@res = 'FALSE'
|
80
95
|
@line = 'vm.unprivileged_userfaultfd'
|
81
|
-
@args = args
|
82
96
|
@tab = 2
|
97
|
+
super
|
83
98
|
end
|
84
99
|
end
|
85
100
|
|
86
101
|
class KExecLoadDisabled < Sysctl::SysKern
|
87
102
|
def initialize(args)
|
88
103
|
@file = '/proc/sys/kernel/kexec_load_disabled'
|
89
|
-
@exp = '1'
|
90
|
-
@res = 'FALSE'
|
91
104
|
@line = 'kernel.kexec_load_disabled'
|
92
|
-
|
105
|
+
super
|
106
|
+
@exp = '1'
|
93
107
|
end
|
94
108
|
end
|
95
109
|
|
96
110
|
class SysRQ < Sysctl::SysKern
|
97
111
|
def initialize(args)
|
98
112
|
@file = '/proc/sys/kernel/sysrq'
|
99
|
-
@exp = '0'
|
100
|
-
@res = 'FALSE'
|
101
113
|
@line = 'kernel.sysrq'
|
102
|
-
@args = args
|
103
114
|
@tab = 4
|
115
|
+
super
|
104
116
|
end
|
105
117
|
end
|
106
118
|
|
107
119
|
class UsernsClone < Sysctl::SysKern
|
108
120
|
def initialize(args)
|
109
121
|
@file = '/proc/sys/kernel/unprivileged_userns_clone'
|
110
|
-
@exp = '0'
|
111
|
-
@res = 'FALSE'
|
112
122
|
@line = 'unprivileged_userns_clone'
|
113
|
-
|
123
|
+
super
|
114
124
|
end
|
115
125
|
end
|
116
126
|
|
117
127
|
class MaxUserNameSpace < Sysctl::SysKern
|
118
128
|
def initialize(args)
|
119
129
|
@file = '/proc/sys/user/max_user_namespaces'
|
120
|
-
@exp = '0'
|
121
|
-
@res = 'FALSE'
|
122
130
|
@line = 'user.max_user_namespaces'
|
123
|
-
|
131
|
+
super
|
124
132
|
end
|
125
133
|
end
|
126
134
|
|
127
135
|
class PerfEventParanoid < Sysctl::SysKern
|
128
136
|
def initialize(args)
|
129
137
|
@file = '/proc/sys/kernel/perf_event_paranoid'
|
130
|
-
@exp = '3'
|
131
|
-
@res = 'FALSE'
|
132
138
|
@line = 'kernel.perf_event_paranoid'
|
133
|
-
|
139
|
+
super
|
140
|
+
@exp = '3'
|
134
141
|
end
|
135
142
|
end
|
136
143
|
|
137
144
|
class YamaPtrace < Sysctl::SysKern
|
138
145
|
def initialize(args)
|
139
146
|
@file = '/proc/sys/kernel/yama/ptrace_scope'
|
140
|
-
@exp = '2'
|
141
|
-
@res = 'FALSE'
|
142
147
|
@line = 'kernel.yama.ptrace_scope'
|
143
|
-
|
148
|
+
super
|
149
|
+
@exp = '2'
|
144
150
|
end
|
145
151
|
end
|
146
152
|
|
147
153
|
class VmMmapRndBits < Sysctl::SysKern
|
148
154
|
def initialize(args)
|
149
155
|
@file = '/proc/sys/vm/mmap_rnd_bits'
|
150
|
-
@exp = '32'
|
151
|
-
@res = 'FALSE'
|
152
156
|
@line = 'vm.mmap_rnd_bits'
|
153
|
-
@args = args
|
154
157
|
@tab = 4
|
158
|
+
super
|
159
|
+
@exp = '32'
|
155
160
|
end
|
156
161
|
end
|
157
162
|
|
158
163
|
class VmMmapRndCompatBits < Sysctl::SysKern
|
159
164
|
def initialize(args)
|
160
165
|
@file = '/proc/sys/vm/mmap_rnd_compat_bits'
|
161
|
-
@exp = '16'
|
162
|
-
@res = 'FALSE'
|
163
166
|
@line = 'vm.mmap_rnd_compat_bits'
|
164
|
-
|
167
|
+
super
|
168
|
+
@exp = '16'
|
165
169
|
end
|
166
170
|
end
|
167
171
|
|
168
172
|
class FsProtectedSymlinks < Sysctl::SysKern
|
169
173
|
def initialize(args)
|
170
174
|
@file = '/proc/sys/fs/protected_symlinks'
|
171
|
-
@exp = '1'
|
172
|
-
@res = 'FALSE'
|
173
175
|
@line = 'fs.protected_symlinks'
|
174
|
-
|
176
|
+
super
|
177
|
+
@exp = '1'
|
175
178
|
end
|
176
179
|
end
|
177
180
|
|
178
181
|
class FsProtectedHardlinks < Sysctl::SysKern
|
179
182
|
def initialize(args)
|
180
183
|
@file = '/proc/sys/fs/protected_hardlinks'
|
181
|
-
@exp = '1'
|
182
|
-
@res = 'FALSE'
|
183
184
|
@line = 'fs.protected_hardlinks'
|
184
|
-
|
185
|
+
super
|
186
|
+
@exp = '1'
|
185
187
|
end
|
186
188
|
end
|
187
189
|
|
188
190
|
class FsProtectedFifos < Sysctl::SysKern
|
189
191
|
def initialize(args)
|
190
192
|
@file = '/proc/sys/fs/protected_fifos'
|
191
|
-
@exp = '2'
|
192
|
-
@res = 'FALSE'
|
193
193
|
@line = 'fs.protected_fifos'
|
194
|
-
@args = args
|
195
194
|
@tab = 4
|
195
|
+
super
|
196
|
+
@exp = '2'
|
196
197
|
end
|
197
198
|
end
|
198
199
|
|
199
200
|
class FsProtectedRegular < Sysctl::SysKern
|
200
201
|
def initialize(args)
|
201
202
|
@file = '/proc/sys/fs/protected_regular'
|
202
|
-
@exp = '2'
|
203
|
-
@res = 'FALSE'
|
204
203
|
@line = 'fs.protected_regular'
|
205
|
-
|
204
|
+
super
|
205
|
+
@exp = '2'
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class FsSuidDumpable < Sysctl::SysKern
|
210
|
+
def initialize(args)
|
211
|
+
@file = '/proc/sys/fs/suid_dumpable'
|
212
|
+
@line = 'fs.suid_dumpable'
|
213
|
+
super
|
214
|
+
@tab = 4
|
206
215
|
end
|
207
216
|
end
|
208
217
|
end
|