Commit | Line | Data |
---|---|---|
525ea79f KB |
1 | #!/bin/sh - |
2 | # | |
07576f30 | 3 | # @(#)security 5.15 (Berkeley) %G% |
525ea79f | 4 | # |
07576f30 KB |
5 | |
6 | # Script to check basic system security. Checks included are: | |
7 | # Users with uid's of 0. | |
8 | # Users without passwords. | |
9 | # Accounts that have been turned off, but still have valid shells. | |
10 | # Special users that have .rhosts files. | |
11 | # Home directory and dot-file ownership and permissions. | |
12 | # Mailbox ownership and permissions. | |
13 | # File list from /etc/mtree/flist.secure. | |
14 | # Dot appearing in root user's path. | |
15 | # NFS file systems globally exported to the world. | |
16 | # Changes in setuid and device files. | |
17 | # Block and character disk device ownership and permissions. | |
18 | # System binaries as described by files in /etc/mtree. | |
19 | ||
fd70cf43 | 20 | PATH=/sbin:/usr/sbin:/bin:/usr/bin |
525ea79f | 21 | |
383148a3 KB |
22 | umask 22 |
23 | ||
40835542 KB |
24 | ERR=/tmp/_secure1.$$ |
25 | TMP1=/tmp/_secure2.$$ | |
26 | TMP2=/tmp/_secure3.$$ | |
27 | LIST=/tmp/_secure4.$$ | |
fd70cf43 | 28 | |
48e0a733 | 29 | trap 'rm -f $ERR $TMP1 $TMP2 $LIST' 0 |
fd70cf43 | 30 | |
07576f30 | 31 | # Check uids. Only root and toor should have a uid of 0. |
8e55538e KB |
32 | echo "" |
33 | echo "Checking for uids of 0:" | |
07576f30 | 34 | awk -F: "\$3 == 0 && \$1 != \"root\" && \$1 != \"toor\" \ |
48e0a733 | 35 | { print \"user \" \$1 \" has a uid of \" \$3 }" /etc/master.passwd |
8e55538e | 36 | |
07576f30 | 37 | # Check for missing passwords. |
8e55538e KB |
38 | echo "" |
39 | echo "Checking for uids without passwords:" | |
48e0a733 KB |
40 | awk -F: "\$2 == \"\" \ |
41 | { print \"user \" \$1 \" has no password\" }" /etc/master.passwd | |
42 | ||
07576f30 | 43 | # If the account is turned off, the shell should be invalid. |
48e0a733 KB |
44 | echo "" |
45 | echo "Checking for turned-off accounts with valid shells:" | |
07576f30 | 46 | awk -F: "length(\$2) != 13 && (\$10 ~ /.*sh$/ || \$10 == \"\") \ |
48e0a733 KB |
47 | { print \"user \" \$1 \" account turned off with valid shell.\" }" \ |
48 | /etc/master.passwd | |
49 | ||
07576f30 KB |
50 | # Check for special users with .rhosts files. Only root and toor should |
51 | # have a .rhosts files. | |
48e0a733 KB |
52 | echo "" |
53 | echo "Checking for special users with .rhosts files." | |
07576f30 KB |
54 | awk -F: "\$1 != \"root\" && \$1 != \"toor\" && \ |
55 | (\$3 < 100 || \$1 == \"ftp\" || \$1 == \"uucp\") \ | |
48e0a733 KB |
56 | { print \$1 \" \" \$6 }" /etc/passwd | \ |
57 | while read uid homedir; do | |
58 | if [ -f ${homedir}/.rhosts ] ; then | |
07576f30 | 59 | rhost=`ls -ldgT ${homedir}/.rhosts` |
48e0a733 KB |
60 | echo "$uid: $rhost" |
61 | fi | |
62 | done | |
63 | ||
64 | # Check home directories. | |
65 | echo "" | |
66 | echo "Checking user's home directories." | |
07576f30 KB |
67 | # Directories should not be owned by someone else or writeable. |
68 | awk -F: "{ print \$1 \" \" \$6 }" /etc/passwd | \ | |
69 | while read uid homedir; do | |
70 | if [ -d ${homedir}/ ] ; then | |
71 | file=`ls -ldgT ${homedir}` | |
72 | echo "$uid $file" | |
73 | fi | |
74 | done | awk \ | |
75 | "\$1 != \$4 && \$4 != \"root\" \ | |
76 | { print \"user \" \$1 \"'s home directory is owned by \" \$4 } \ | |
77 | \$2 ~ /^-....w/ \ | |
78 | { print \"user \" \$1 \"'s home directory is group writeable\" } \ | |
79 | \$2 ~ /^-.......w/ \ | |
80 | { print \"user \" \$1 \"'s home directory is other writeable\" }" | |
81 | ||
82 | echo "" | |
83 | echo "Checking .netrc, .rhosts files." | |
48e0a733 KB |
84 | # Files that should not be owned by someone else or readable. |
85 | awk -F: "{ print \$1 \" \" \$6 }" /etc/passwd | \ | |
86 | while read uid homedir; do | |
87 | if [ -f ${homedir}/.netrc ] ; then | |
07576f30 | 88 | file=`ls -ldgT ${homedir}/.netrc` |
48e0a733 KB |
89 | echo "$uid .netrc $file" |
90 | fi | |
91 | if [ -f ${homedir}/.rhosts ] ; then | |
07576f30 | 92 | file=`ls -ldgT ${homedir}/.rhosts` |
48e0a733 KB |
93 | echo "$uid .rhosts $file" |
94 | fi | |
95 | done | awk \ | |
96 | "\$1 != \$5 && \$5 != \"root\" \ | |
97 | { print \"user \" \$1 \"'s \" \$2 \" file is owned by \" \$5 } \ | |
98 | \$3 ~ /^-...r/ \ | |
99 | { print \"user \" \$1 \"'s \" \$2 \" file is group readable\" } \ | |
100 | \$3 ~ /^-......r/ \ | |
101 | { print \"user \" \$1 \"'s \" \$2 \" file is other readable\" } \ | |
102 | \$3 ~ /^-....w/ \ | |
103 | { print \"user \" \$1 \"'s \" \$2 \" file is group writeable\" } \ | |
104 | \$3 ~ /^-.......w/ \ | |
105 | { print \"user \" \$1 \"'s \" \$2 \" file is other writeable\" }" | |
106 | ||
107 | # Files that should not be owned by someone else or writeable. | |
108 | echo "" | |
07576f30 | 109 | echo "Checking .cshrc, .klogin, .login, .profile files." |
48e0a733 KB |
110 | awk -F: "{ print \$1 \" \" \$6 }" /etc/passwd | \ |
111 | while read uid homedir; do | |
112 | if [ -f ${homedir}/.cshrc ] ; then | |
07576f30 | 113 | file=`ls -ldgT ${homedir}/.cshrc` |
48e0a733 KB |
114 | echo "$uid .cshrc $file" |
115 | fi | |
116 | if [ -f ${homedir}/.klogin ] ; then | |
07576f30 | 117 | file=`ls -ldgT ${homedir}/.klogin` |
48e0a733 KB |
118 | echo "$uid .klogin $file" |
119 | fi | |
120 | if [ -f ${homedir}/.login ] ; then | |
07576f30 | 121 | file=`ls -ldgT ${homedir}/.login` |
48e0a733 KB |
122 | echo "$uid .login $file" |
123 | fi | |
124 | if [ -f ${homedir}/.profile ] ; then | |
07576f30 | 125 | file=`ls -ldgT ${homedir}/.profile` |
48e0a733 KB |
126 | echo "$uid .profile $file" |
127 | fi | |
128 | done | awk \ | |
129 | "\$1 != \$5 && \$5 != \"root\" \ | |
130 | { print \"user \" \$1 \"'s \" \$2 \" file is owned by \" \$5 } \ | |
131 | \$3 ~ /^-....w/ \ | |
132 | { print \"user \" \$1 \"'s \" \$2 \" file is group writeable\" } \ | |
133 | \$3 ~ /^-.......w/ \ | |
134 | { print \"user \" \$1 \"'s \" \$2 \" file is other writeable\" }" | |
135 | ||
136 | # Check mailbox ownership and permissions. | |
137 | echo "" | |
138 | echo "Checking mailbox ownership." | |
139 | ls -l /var/mail | \ | |
140 | awk "\$3 != \$9 \ | |
141 | { print \"user \" \$9 \"'s mailbox is owned by \" \$3 } \ | |
142 | \$2 ~ /^-...r/ \ | |
143 | { print \"user \" \$1 \"'s mailbox is group readable\" } \ | |
144 | \$2 ~ /^-......r/ \ | |
145 | { print \"user \" \$1 \"'s mailbox is other readable\" } \ | |
146 | \$2 ~ /^-....w/ \ | |
147 | { print \"user \" \$1 \"'s mailbox is group writeable\" } \ | |
148 | \$2 ~ /^-.......w/ \ | |
149 | { print \"user \" \$1 \"'s mailbox is other writeable\" }" | |
150 | ||
151 | # Check for special files. | |
152 | echo "" | |
153 | echo "Checking dangerous files and directories." | |
154 | mtree -e -p / -f /etc/mtree/flist.secure | |
155 | ||
156 | # Check for bad paths in root startup files. | |
157 | echo "" | |
158 | echo "Checking root paths (csh startup files)." | |
159 | rhome=/root | |
160 | for i in /etc/csh.cshrc /etc/csh.login ${rhome}/.cshrc ${rhome}/.login ; do | |
161 | echo "$i:" | |
162 | if [ -f $i ] ; then | |
163 | if egrep -h -i 'path.*[^a-z]\.[^a-z]' $i > /dev/null ; then | |
164 | echo "Root's path appears to include ." | |
165 | fi | |
166 | egrep -h -i path $i | \ | |
167 | awk "{ for (i = 1; i <= NF; ++i) print \$i }" | \ | |
168 | while read dir; do | |
169 | if [ -d $dir ] ; then | |
170 | echo `ls -ldgT $dir` | |
171 | fi | |
172 | done | \ | |
173 | awk "\$1 ~ /^d....w/ \ | |
174 | { print \"Root path directory \" \$10 \" is group writeable.\" } \ | |
175 | \$1 ~ /^d.......w/ \ | |
176 | { print \"Root path directory \" \$10 \" is other writeable.\" }" | |
177 | fi | |
178 | done | |
179 | ||
180 | echo "" | |
181 | echo "Checking root paths (sh startup files)." | |
182 | for i in ${rhome}/.profile ${rhome}/.klogin ; do | |
183 | echo "$i:" | |
184 | if [ -f $i ] ; then | |
185 | if egrep -h -i 'path.*:\.:' $i > /dev/null ; then | |
186 | echo "Root's path appears to include ." | |
187 | fi | |
188 | egrep -h -i 'path.*:' $i | \ | |
189 | awk -F: "{ for (i = 1; i <= NF; ++i) print \$i }" | \ | |
190 | while read dir; do | |
191 | if [ -d $dir ] ; then | |
192 | echo `ls -ldgT $dir` | |
193 | fi | |
194 | done | \ | |
195 | awk "\$1 ~ /^d....w/ \ | |
196 | { print \"Root path directory \" \$10 \" is group writeable.\" } \ | |
197 | \$1 ~ /^d.......w/ \ | |
198 | { print \"Root path directory \" \$10 \" is other writeable.\" }" | |
199 | fi | |
200 | done | |
8e55538e | 201 | |
07576f30 KB |
202 | # Check for globally exported file systems. |
203 | echo "" | |
204 | echo "Checking for globally exported file systems." | |
205 | awk '{ | |
206 | readonly = 0; | |
207 | for (i = 2; i <= NF; ++i) { | |
208 | if ($i ~ /-ro/) | |
209 | readonly = 1; | |
210 | else if ($i !~ /^-/) | |
211 | next; | |
212 | } | |
213 | if (readonly) | |
214 | print "File system " $1 " globally exported, read-only." | |
215 | else | |
216 | print "File system " $1 " globally exported, read-write." | |
217 | }' < /etc/exports | |
218 | ||
40835542 | 219 | # Display setuid and device changes. |
32e3fbdd | 220 | echo "" |
773dea30 | 221 | echo "Checking setuid files and devices:" |
07576f30 | 222 | (find /dev ! -fstype local -a -prune -o \ |
8e55538e | 223 | \( -perm -u+s -o -perm -g+s -o ! -type d -a ! -type f -a ! -type l \) | \ |
07576f30 | 224 | sort | sed -e 's/^/ls -ldgT /' | sh >$TMP1) 2>$ERR |
383148a3 | 225 | |
40835542 KB |
226 | # Display any errors that occurred during system file walk. |
227 | if [ -s $ERR ] ; then | |
228 | echo "Setuid/device find errors:" | |
229 | cat $ERR | |
8e55538e | 230 | echo "" |
383148a3 KB |
231 | fi |
232 | ||
40835542 KB |
233 | # Display any changes in the setuid file list. |
234 | egrep -v '^[bc]' $TMP1 > $LIST | |
8e55538e | 235 | if [ -s $LIST ] ; then |
40835542 KB |
236 | CUR=/var/log/setuid.current |
237 | BACK=/var/log/setuid.backup | |
383148a3 | 238 | |
40835542 KB |
239 | if [ -s $CUR ] ; then |
240 | if cmp -s $CUR $LIST ; then | |
8e55538e KB |
241 | : |
242 | else | |
40835542 KB |
243 | :> $TMP1 |
244 | join -110 -210 -v2 $CUR $LIST >$TMP2 | |
245 | if [ -s $TMP2 ] ; then | |
246 | echo "Setuid additions:" | |
247 | tee -a $TMP1 < $TMP2 | |
8e55538e KB |
248 | echo "" |
249 | fi | |
250 | ||
40835542 KB |
251 | join -110 -210 -v1 $CUR $LIST >$TMP2 |
252 | if [ -s $TMP2 ] ; then | |
253 | echo "Setuid deletions:" | |
254 | tee -a $TMP1 < $TMP2 | |
8e55538e KB |
255 | echo "" |
256 | fi | |
257 | ||
40835542 KB |
258 | sort +9 $TMP1 $CUR $LIST | \ |
259 | sed -e 's/[ ][ ]*/ /g' | uniq -u >$TMP2 | |
260 | if [ -s $TMP2 ] ; then | |
261 | echo "Setuid changes:" | |
262 | column $TMP2 | |
8e55538e KB |
263 | echo "" |
264 | fi | |
265 | ||
40835542 KB |
266 | mv $CUR $BACK |
267 | mv $LIST $CUR | |
8e55538e KB |
268 | fi |
269 | else | |
40835542 | 270 | echo "Setuid additions:" |
8e55538e KB |
271 | cat $LIST |
272 | echo "" | |
40835542 | 273 | mv $LIST $CUR |
8e55538e | 274 | fi |
525ea79f | 275 | fi |
525ea79f | 276 | |
07576f30 KB |
277 | # Check for readable/writeable block and character disk devices. |
278 | echo "" | |
279 | echo "Checking disk device ownership and permissions." | |
280 | egrep '^b' $TMP1 > $LIST | |
281 | egrep '^c.*/rdk[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
282 | egrep '^c.*/rfd[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
283 | egrep '^c.*/rhd[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
284 | egrep '^c.*/rhk[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
285 | egrep '^c.*/rhp[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
286 | egrep '^c.*/rjb[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
287 | egrep '^c.*/rkra[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
288 | egrep '^c.*/rra[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
289 | egrep '^c.*/rrb[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
290 | egrep '^c.*/rrd[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
291 | egrep '^c.*/rrl[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
292 | egrep '^c.*/rrx[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
293 | egrep '^c.*/rrz[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
294 | egrep '^c.*/rsd[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
295 | egrep '^c.*/rup[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
296 | egrep '^c.*/rwd[0-9][0-9]*[a-h]$' $TMP1 >> $LIST | |
297 | ||
298 | awk "\$4 != \"operator\" \ | |
299 | { print \"Device \" \$11 \" not owned by group operator.\" }" < $LIST | |
300 | awk "\$1 ~ /^c....w/ \ | |
301 | { print \"Device \" \$11 \" is group writeable.\" } \ | |
302 | \$1 ~ /^c.......w/ \ | |
303 | { print \"Device \" \$11 \" is other writeable.\" }" < $LIST | |
304 | ||
305 | egrep '^[bcs]' $TMP1 > $LIST | |
40835542 | 306 | # Display any changes in the device file list. |
40835542 KB |
307 | if [ -s $LIST ] ; then |
308 | CUR=/var/log/device.current | |
309 | BACK=/var/log/device.backup | |
310 | ||
311 | if [ -s $CUR ] ; then | |
312 | if cmp -s $CUR $LIST ; then | |
313 | : | |
314 | else | |
315 | :> $TMP1 | |
316 | join -111 -211 -v2 $CUR $LIST >$TMP2 | |
317 | if [ -s $TMP2 ] ; then | |
318 | echo "Device additions:" | |
319 | tee -a $TMP1 < $TMP2 | |
320 | echo "" | |
321 | fi | |
322 | ||
323 | join -111 -211 -v1 $CUR $LIST >$TMP2 | |
324 | if [ -s $TMP2 ] ; then | |
325 | echo "Device deletions:" | |
326 | tee -a $TMP1 < $TMP2 | |
327 | echo "" | |
328 | fi | |
329 | ||
330 | sort +10 $TMP1 $CUR $LIST | \ | |
331 | sed -e 's/[ ][ ]*/ /g' | uniq -u >$TMP2 | |
332 | if [ -s $TMP2 ] ; then | |
333 | echo "Device changes:" | |
334 | column $TMP2 | |
335 | echo "" | |
336 | fi | |
337 | ||
338 | mv $CUR $BACK | |
339 | mv $LIST $CUR | |
340 | fi | |
341 | else | |
342 | echo "Device additions:" | |
343 | cat $LIST | |
344 | echo "" | |
345 | mv $LIST $CUR | |
346 | fi | |
347 | fi | |
40835542 | 348 | |
fd70cf43 KB |
349 | # Check the system binaries. |
350 | # Create the mtree tree specifications using: | |
351 | # | |
48e0a733 KB |
352 | # mtree -cx -pDIR -kcksum,gid,mode,nlink,size,link,time,uid |
353 | # DIR.secure | |
fd70cf43 KB |
354 | # chown bin.bin DIR.SECURE |
355 | # chmod 444 DIR.SECURE | |
356 | # | |
357 | # Note, this is not complete protection against Trojan horsed binaries, as | |
358 | # the hacker can modify the tree specification to match the replaced binary. | |
359 | # For details on really protecting yourself against modified binaries, see | |
360 | # the mtree(8) manual page. | |
fd70cf43 KB |
361 | if cd /etc/mtree; then |
362 | echo "" | |
363 | echo "Checking system binaries:" | |
364 | for file in *.secure; do | |
365 | tree=`sed -n -e '3s/.* //p' -e 3q $file` | |
366 | echo "" | |
367 | echo "Checking $tree:" | |
368 | mtree -f $file -p $tree | |
369 | done | |
370 | fi |