Commit 4c37c7a52c80a2f865e376af6acc01a86ecf887c
1 parent
d109192c79
Exists in
master
added checksec script
Showing 1 changed file with 882 additions and 0 deletions Side-by-side Diff
scripts/checksec.sh
View file @
4c37c7a
1 | +#!/bin/bash | |
2 | +# | |
3 | +# The BSD License (http://www.opensource.org/licenses/bsd-license.php) | |
4 | +# specifies the terms and conditions of use for checksec.sh: | |
5 | +# | |
6 | +# Copyright (c) 2009-2011, Tobias Klein. | |
7 | +# All rights reserved. | |
8 | +# | |
9 | +# Redistribution and use in source and binary forms, with or without | |
10 | +# modification, are permitted provided that the following conditions | |
11 | +# are met: | |
12 | +# | |
13 | +# * Redistributions of source code must retain the above copyright | |
14 | +# notice, this list of conditions and the following disclaimer. | |
15 | +# * Redistributions in binary form must reproduce the above copyright | |
16 | +# notice, this list of conditions and the following disclaimer in | |
17 | +# the documentation and/or other materials provided with the | |
18 | +# distribution. | |
19 | +# * Neither the name of Tobias Klein nor the name of trapkit.de may be | |
20 | +# used to endorse or promote products derived from this software | |
21 | +# without specific prior written permission. | |
22 | +# | |
23 | +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
24 | +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
25 | +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
26 | +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
27 | +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
28 | +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
29 | +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | |
30 | +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
31 | +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
32 | +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |
33 | +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH | |
34 | +# DAMAGE. | |
35 | +# | |
36 | +# Name : checksec.sh | |
37 | +# Version : 1.5 | |
38 | +# Author : Tobias Klein | |
39 | +# Date : November 2011 | |
40 | +# Download: http://www.trapkit.de/tools/checksec.html | |
41 | +# Changes : http://www.trapkit.de/tools/checksec_changes.txt | |
42 | +# | |
43 | +# Description: | |
44 | +# | |
45 | +# Modern Linux distributions offer some mitigation techniques to make it | |
46 | +# harder to exploit software vulnerabilities reliably. Mitigations such | |
47 | +# as RELRO, NoExecute (NX), Stack Canaries, Address Space Layout | |
48 | +# Randomization (ASLR) and Position Independent Executables (PIE) have | |
49 | +# made reliably exploiting any vulnerabilities that do exist far more | |
50 | +# challenging. The checksec.sh script is designed to test what *standard* | |
51 | +# Linux OS and PaX (http://pax.grsecurity.net/) security features are being | |
52 | +# used. | |
53 | +# | |
54 | +# As of version 1.3 the script also lists the status of various Linux kernel | |
55 | +# protection mechanisms. | |
56 | +# | |
57 | +# Credits: | |
58 | +# | |
59 | +# Thanks to Brad Spengler (grsecurity.net) for the PaX support. | |
60 | +# Thanks to Jon Oberheide (jon.oberheide.org) for the kernel support. | |
61 | +# Thanks to Ollie Whitehouse (Research In Motion) for rpath/runpath support. | |
62 | +# | |
63 | +# Others that contributed to checksec.sh (in no particular order): | |
64 | +# | |
65 | +# Simon Ruderich, Denis Scherbakov, Stefan Kuttler, Radoslaw Madej, | |
66 | +# Anthony G. Basile, Martin Vaeth and Brian Davis. | |
67 | +# | |
68 | + | |
69 | +# global vars | |
70 | +have_readelf=1 | |
71 | +verbose=false | |
72 | + | |
73 | +# FORTIFY_SOURCE vars | |
74 | +FS_end=_chk | |
75 | +FS_cnt_total=0 | |
76 | +FS_cnt_checked=0 | |
77 | +FS_cnt_unchecked=0 | |
78 | +FS_chk_func_libc=0 | |
79 | +FS_functions=0 | |
80 | +FS_libc=0 | |
81 | + | |
82 | +# version information | |
83 | +version() { | |
84 | + echo "checksec v1.5, Tobias Klein, www.trapkit.de, November 2011" | |
85 | + echo | |
86 | +} | |
87 | + | |
88 | +# help | |
89 | +help() { | |
90 | + echo "Usage: checksec [OPTION]" | |
91 | + echo | |
92 | + echo "Options:" | |
93 | + echo | |
94 | + echo " --file <executable-file>" | |
95 | + echo " --dir <directory> [-v]" | |
96 | + echo " --proc <process name>" | |
97 | + echo " --proc-all" | |
98 | + echo " --proc-libs <process ID>" | |
99 | + echo " --kernel" | |
100 | + echo " --fortify-file <executable-file>" | |
101 | + echo " --fortify-proc <process ID>" | |
102 | + echo " --version" | |
103 | + echo " --help" | |
104 | + echo | |
105 | + echo "For more information, see:" | |
106 | + echo " http://www.trapkit.de/tools/checksec.html" | |
107 | + echo | |
108 | +} | |
109 | + | |
110 | +# check if command exists | |
111 | +command_exists () { | |
112 | + type $1 > /dev/null 2>&1; | |
113 | +} | |
114 | + | |
115 | +# check if directory exists | |
116 | +dir_exists () { | |
117 | + if [ -d $1 ] ; then | |
118 | + return 0 | |
119 | + else | |
120 | + return 1 | |
121 | + fi | |
122 | +} | |
123 | + | |
124 | +# check user privileges | |
125 | +root_privs () { | |
126 | + if [ $(/usr/bin/id -u) -eq 0 ] ; then | |
127 | + return 0 | |
128 | + else | |
129 | + return 1 | |
130 | + fi | |
131 | +} | |
132 | + | |
133 | +# check if input is numeric | |
134 | +isNumeric () { | |
135 | + echo "$@" | grep -q -v "[^0-9]" | |
136 | +} | |
137 | + | |
138 | +# check if input is a string | |
139 | +isString () { | |
140 | + echo "$@" | grep -q -v "[^A-Za-z]" | |
141 | +} | |
142 | + | |
143 | +# check file(s) | |
144 | +filecheck() { | |
145 | + # check for RELRO support | |
146 | + if readelf -l $1 2>/dev/null | grep -q 'GNU_RELRO'; then | |
147 | + if readelf -d $1 2>/dev/null | grep -q 'BIND_NOW'; then | |
148 | + echo -n -e '\033[32mFull RELRO \033[m ' | |
149 | + else | |
150 | + echo -n -e '\033[33mPartial RELRO\033[m ' | |
151 | + fi | |
152 | + else | |
153 | + echo -n -e '\033[31mNo RELRO \033[m ' | |
154 | + fi | |
155 | + | |
156 | + # check for stack canary support | |
157 | + if readelf -s $1 2>/dev/null | grep -q '__stack_chk_fail'; then | |
158 | + echo -n -e '\033[32mCanary found \033[m ' | |
159 | + else | |
160 | + echo -n -e '\033[31mNo canary found\033[m ' | |
161 | + fi | |
162 | + | |
163 | + # check for NX support | |
164 | + if readelf -W -l $1 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then | |
165 | + echo -n -e '\033[31mNX disabled\033[m ' | |
166 | + else | |
167 | + echo -n -e '\033[32mNX enabled \033[m ' | |
168 | + fi | |
169 | + | |
170 | + # check for PIE support | |
171 | + if readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then | |
172 | + echo -n -e '\033[31mNo PIE \033[m ' | |
173 | + elif readelf -h $1 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then | |
174 | + if readelf -d $1 2>/dev/null | grep -q '(DEBUG)'; then | |
175 | + echo -n -e '\033[32mPIE enabled \033[m ' | |
176 | + else | |
177 | + echo -n -e '\033[33mDSO \033[m ' | |
178 | + fi | |
179 | + else | |
180 | + echo -n -e '\033[33mNot an ELF file\033[m ' | |
181 | + fi | |
182 | + | |
183 | + # check for rpath / run path | |
184 | + if readelf -d $1 2>/dev/null | grep -q 'rpath'; then | |
185 | + echo -n -e '\033[31mRPATH \033[m ' | |
186 | + else | |
187 | + echo -n -e '\033[32mNo RPATH \033[m ' | |
188 | + fi | |
189 | + | |
190 | + if readelf -d $1 2>/dev/null | grep -q 'runpath'; then | |
191 | + echo -n -e '\033[31mRUNPATH \033[m ' | |
192 | + else | |
193 | + echo -n -e '\033[32mNo RUNPATH \033[m ' | |
194 | + fi | |
195 | +} | |
196 | + | |
197 | +# check process(es) | |
198 | +proccheck() { | |
199 | + # check for RELRO support | |
200 | + if readelf -l $1/exe 2>/dev/null | grep -q 'Program Headers'; then | |
201 | + if readelf -l $1/exe 2>/dev/null | grep -q 'GNU_RELRO'; then | |
202 | + if readelf -d $1/exe 2>/dev/null | grep -q 'BIND_NOW'; then | |
203 | + echo -n -e '\033[32mFull RELRO \033[m ' | |
204 | + else | |
205 | + echo -n -e '\033[33mPartial RELRO \033[m ' | |
206 | + fi | |
207 | + else | |
208 | + echo -n -e '\033[31mNo RELRO \033[m ' | |
209 | + fi | |
210 | + else | |
211 | + echo -n -e '\033[31mPermission denied (please run as root)\033[m\n' | |
212 | + exit 1 | |
213 | + fi | |
214 | + | |
215 | + # check for stack canary support | |
216 | + if readelf -s $1/exe 2>/dev/null | grep -q 'Symbol table'; then | |
217 | + if readelf -s $1/exe 2>/dev/null | grep -q '__stack_chk_fail'; then | |
218 | + echo -n -e '\033[32mCanary found \033[m ' | |
219 | + else | |
220 | + echo -n -e '\033[31mNo canary found \033[m ' | |
221 | + fi | |
222 | + else | |
223 | + if [ "$1" != "1" ] ; then | |
224 | + echo -n -e '\033[33mPermission denied \033[m ' | |
225 | + else | |
226 | + echo -n -e '\033[33mNo symbol table found\033[m ' | |
227 | + fi | |
228 | + fi | |
229 | + | |
230 | + # first check for PaX support | |
231 | + if cat $1/status 2> /dev/null | grep -q 'PaX:'; then | |
232 | + pageexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b6) ) | |
233 | + segmexec=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b10) ) | |
234 | + mprotect=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b8) ) | |
235 | + randmmap=( $(cat $1/status 2> /dev/null | grep 'PaX:' | cut -b9) ) | |
236 | + if [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "R" ]] ; then | |
237 | + echo -n -e '\033[32mPaX enabled\033[m ' | |
238 | + elif [[ "$pageexec" = "p" && "$segmexec" = "s" && "$randmmap" = "R" ]] ; then | |
239 | + echo -n -e '\033[33mPaX ASLR only\033[m ' | |
240 | + elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "R" ]] ; then | |
241 | + echo -n -e '\033[33mPaX mprot off \033[m' | |
242 | + elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "M" && "$randmmap" = "r" ]] ; then | |
243 | + echo -n -e '\033[33mPaX ASLR off\033[m ' | |
244 | + elif [[ "$pageexec" = "P" || "$segmexec" = "S" ]] && [[ "$mprotect" = "m" && "$randmmap" = "r" ]] ; then | |
245 | + echo -n -e '\033[33mPaX NX only\033[m ' | |
246 | + else | |
247 | + echo -n -e '\033[31mPaX disabled\033[m ' | |
248 | + fi | |
249 | + # fallback check for NX support | |
250 | + elif readelf -W -l $1/exe 2>/dev/null | grep 'GNU_STACK' | grep -q 'RWE'; then | |
251 | + echo -n -e '\033[31mNX disabled\033[m ' | |
252 | + else | |
253 | + echo -n -e '\033[32mNX enabled \033[m ' | |
254 | + fi | |
255 | + | |
256 | + # check for PIE support | |
257 | + if readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*EXEC'; then | |
258 | + echo -n -e '\033[31mNo PIE \033[m ' | |
259 | + elif readelf -h $1/exe 2>/dev/null | grep -q 'Type:[[:space:]]*DYN'; then | |
260 | + if readelf -d $1/exe 2>/dev/null | grep -q '(DEBUG)'; then | |
261 | + echo -n -e '\033[32mPIE enabled \033[m ' | |
262 | + else | |
263 | + echo -n -e '\033[33mDynamic Shared Object\033[m ' | |
264 | + fi | |
265 | + else | |
266 | + echo -n -e '\033[33mNot an ELF file \033[m ' | |
267 | + fi | |
268 | +} | |
269 | + | |
270 | +# check mapped libraries | |
271 | +libcheck() { | |
272 | + libs=( $(awk '{ print $6 }' /proc/$1/maps | grep '/' | sort -u | xargs file | grep ELF | awk '{ print $1 }' | sed 's/:/ /') ) | |
273 | + | |
274 | + printf "\n* Loaded libraries (file information, # of mapped files: ${#libs[@]}):\n\n" | |
275 | + | |
276 | + for element in $(seq 0 $((${#libs[@]} - 1))) | |
277 | + do | |
278 | + echo " ${libs[$element]}:" | |
279 | + echo -n " " | |
280 | + filecheck ${libs[$element]} | |
281 | + printf "\n\n" | |
282 | + done | |
283 | +} | |
284 | + | |
285 | +# check for system-wide ASLR support | |
286 | +aslrcheck() { | |
287 | + # PaX ASLR support | |
288 | + if !(cat /proc/1/status 2> /dev/null | grep -q 'Name:') ; then | |
289 | + echo -n -e ':\033[33m insufficient privileges for PaX ASLR checks\033[m\n' | |
290 | + echo -n -e ' Fallback to standard Linux ASLR check' | |
291 | + fi | |
292 | + | |
293 | + if cat /proc/1/status 2> /dev/null | grep -q 'PaX:'; then | |
294 | + printf ": " | |
295 | + if cat /proc/1/status 2> /dev/null | grep 'PaX:' | grep -q 'R'; then | |
296 | + echo -n -e '\033[32mPaX ASLR enabled\033[m\n\n' | |
297 | + else | |
298 | + echo -n -e '\033[31mPaX ASLR disabled\033[m\n\n' | |
299 | + fi | |
300 | + else | |
301 | + # standard Linux 'kernel.randomize_va_space' ASLR support | |
302 | + # (see the kernel file 'Documentation/sysctl/kernel.txt' for a detailed description) | |
303 | + printf " (kernel.randomize_va_space): " | |
304 | + if /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 1'; then | |
305 | + echo -n -e '\033[33mOn (Setting: 1)\033[m\n\n' | |
306 | + printf " Description - Make the addresses of mmap base, stack and VDSO page randomized.\n" | |
307 | + printf " This, among other things, implies that shared libraries will be loaded to \n" | |
308 | + printf " random addresses. Also for PIE-linked binaries, the location of code start\n" | |
309 | + printf " is randomized. Heap addresses are *not* randomized.\n\n" | |
310 | + elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 2'; then | |
311 | + echo -n -e '\033[32mOn (Setting: 2)\033[m\n\n' | |
312 | + printf " Description - Make the addresses of mmap base, heap, stack and VDSO page randomized.\n" | |
313 | + printf " This, among other things, implies that shared libraries will be loaded to random \n" | |
314 | + printf " addresses. Also for PIE-linked binaries, the location of code start is randomized.\n\n" | |
315 | + elif /sbin/sysctl -a 2>/dev/null | grep -q 'kernel.randomize_va_space = 0'; then | |
316 | + echo -n -e '\033[31mOff (Setting: 0)\033[m\n' | |
317 | + else | |
318 | + echo -n -e '\033[31mNot supported\033[m\n' | |
319 | + fi | |
320 | + printf " See the kernel file 'Documentation/sysctl/kernel.txt' for more details.\n\n" | |
321 | + fi | |
322 | +} | |
323 | + | |
324 | +# check cpu nx flag | |
325 | +nxcheck() { | |
326 | + if grep -q nx /proc/cpuinfo; then | |
327 | + echo -n -e '\033[32mYes\033[m\n\n' | |
328 | + else | |
329 | + echo -n -e '\033[31mNo\033[m\n\n' | |
330 | + fi | |
331 | +} | |
332 | + | |
333 | +# check for kernel protection mechanisms | |
334 | +kernelcheck() { | |
335 | + printf " Description - List the status of kernel protection mechanisms. Rather than\n" | |
336 | + printf " inspect kernel mechanisms that may aid in the prevention of exploitation of\n" | |
337 | + printf " userspace processes, this option lists the status of kernel configuration\n" | |
338 | + printf " options that harden the kernel itself against attack.\n\n" | |
339 | + printf " Kernel config: " | |
340 | + | |
341 | + if [ -f /proc/config.gz ] ; then | |
342 | + kconfig="zcat /proc/config.gz" | |
343 | + printf "\033[32m/proc/config.gz\033[m\n\n" | |
344 | + elif [ -f /boot/config-`uname -r` ] ; then | |
345 | + kconfig="cat /boot/config-`uname -r`" | |
346 | + printf "\033[33m/boot/config-`uname -r`\033[m\n\n" | |
347 | + printf " Warning: The config on disk may not represent running kernel config!\n\n"; | |
348 | + elif [ -f "${KBUILD_OUTPUT:-/usr/src/linux}"/.config ] ; then | |
349 | + kconfig="cat ${KBUILD_OUTPUT:-/usr/src/linux}/.config" | |
350 | + printf "\033[33m%s\033[m\n\n" "${KBUILD_OUTPUT:-/usr/src/linux}/.config" | |
351 | + printf " Warning: The config on disk may not represent running kernel config!\n\n"; | |
352 | + else | |
353 | + printf "\033[31mNOT FOUND\033[m\n\n" | |
354 | + exit 0 | |
355 | + fi | |
356 | + | |
357 | + printf " GCC stack protector support: " | |
358 | + if $kconfig | grep -qi 'CONFIG_CC_STACKPROTECTOR=y'; then | |
359 | + printf "\033[32mEnabled\033[m\n" | |
360 | + else | |
361 | + printf "\033[31mDisabled\033[m\n" | |
362 | + fi | |
363 | + | |
364 | + printf " Strict user copy checks: " | |
365 | + if $kconfig | grep -qi 'CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y'; then | |
366 | + printf "\033[32mEnabled\033[m\n" | |
367 | + else | |
368 | + printf "\033[31mDisabled\033[m\n" | |
369 | + fi | |
370 | + | |
371 | + printf " Enforce read-only kernel data: " | |
372 | + if $kconfig | grep -qi 'CONFIG_DEBUG_RODATA=y'; then | |
373 | + printf "\033[32mEnabled\033[m\n" | |
374 | + else | |
375 | + printf "\033[31mDisabled\033[m\n" | |
376 | + fi | |
377 | + printf " Restrict /dev/mem access: " | |
378 | + if $kconfig | grep -qi 'CONFIG_STRICT_DEVMEM=y'; then | |
379 | + printf "\033[32mEnabled\033[m\n" | |
380 | + else | |
381 | + printf "\033[31mDisabled\033[m\n" | |
382 | + fi | |
383 | + | |
384 | + printf " Restrict /dev/kmem access: " | |
385 | + if $kconfig | grep -qi 'CONFIG_DEVKMEM=y'; then | |
386 | + printf "\033[31mDisabled\033[m\n" | |
387 | + else | |
388 | + printf "\033[32mEnabled\033[m\n" | |
389 | + fi | |
390 | + | |
391 | + printf "\n" | |
392 | + printf "* grsecurity / PaX: " | |
393 | + | |
394 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC=y'; then | |
395 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIGH=y'; then | |
396 | + printf "\033[32mHigh GRKERNSEC\033[m\n\n" | |
397 | + elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_MEDIUM=y'; then | |
398 | + printf "\033[33mMedium GRKERNSEC\033[m\n\n" | |
399 | + elif $kconfig | grep -qi 'CONFIG_GRKERNSEC_LOW=y'; then | |
400 | + printf "\033[31mLow GRKERNSEC\033[m\n\n" | |
401 | + else | |
402 | + printf "\033[33mCustom GRKERNSEC\033[m\n\n" | |
403 | + fi | |
404 | + | |
405 | + printf " Non-executable kernel pages: " | |
406 | + if $kconfig | grep -qi 'CONFIG_PAX_KERNEXEC=y'; then | |
407 | + printf "\033[32mEnabled\033[m\n" | |
408 | + else | |
409 | + printf "\033[31mDisabled\033[m\n" | |
410 | + fi | |
411 | + | |
412 | + printf " Prevent userspace pointer deref: " | |
413 | + if $kconfig | grep -qi 'CONFIG_PAX_MEMORY_UDEREF=y'; then | |
414 | + printf "\033[32mEnabled\033[m\n" | |
415 | + else | |
416 | + printf "\033[31mDisabled\033[m\n" | |
417 | + fi | |
418 | + | |
419 | + printf " Prevent kobject refcount overflow: " | |
420 | + if $kconfig | grep -qi 'CONFIG_PAX_REFCOUNT=y'; then | |
421 | + printf "\033[32mEnabled\033[m\n" | |
422 | + else | |
423 | + printf "\033[31mDisabled\033[m\n" | |
424 | + fi | |
425 | + | |
426 | + printf " Bounds check heap object copies: " | |
427 | + if $kconfig | grep -qi 'CONFIG_PAX_USERCOPY=y'; then | |
428 | + printf "\033[32mEnabled\033[m\n" | |
429 | + else | |
430 | + printf "\033[31mDisabled\033[m\n" | |
431 | + fi | |
432 | + | |
433 | + printf " Disable writing to kmem/mem/port: " | |
434 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC_KMEM=y'; then | |
435 | + printf "\033[32mEnabled\033[m\n" | |
436 | + else | |
437 | + printf "\033[31mDisabled\033[m\n" | |
438 | + fi | |
439 | + | |
440 | + printf " Disable privileged I/O: " | |
441 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC_IO=y'; then | |
442 | + printf "\033[32mEnabled\033[m\n" | |
443 | + else | |
444 | + printf "\033[31mDisabled\033[m\n" | |
445 | + fi | |
446 | + | |
447 | + printf " Harden module auto-loading: " | |
448 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC_MODHARDEN=y'; then | |
449 | + printf "\033[32mEnabled\033[m\n" | |
450 | + else | |
451 | + printf "\033[31mDisabled\033[m\n" | |
452 | + fi | |
453 | + | |
454 | + printf " Hide kernel symbols: " | |
455 | + if $kconfig | grep -qi 'CONFIG_GRKERNSEC_HIDESYM=y'; then | |
456 | + printf "\033[32mEnabled\033[m\n" | |
457 | + else | |
458 | + printf "\033[31mDisabled\033[m\n" | |
459 | + fi | |
460 | + else | |
461 | + printf "\033[31mNo GRKERNSEC\033[m\n\n" | |
462 | + printf " The grsecurity / PaX patchset is available here:\n" | |
463 | + printf " http://grsecurity.net/\n" | |
464 | + fi | |
465 | + | |
466 | + printf "\n" | |
467 | + printf "* Kernel Heap Hardening: " | |
468 | + | |
469 | + if $kconfig | grep -qi 'CONFIG_KERNHEAP=y'; then | |
470 | + if $kconfig | grep -qi 'CONFIG_KERNHEAP_FULLPOISON=y'; then | |
471 | + printf "\033[32mFull KERNHEAP\033[m\n\n" | |
472 | + else | |
473 | + printf "\033[33mPartial KERNHEAP\033[m\n\n" | |
474 | + fi | |
475 | + else | |
476 | + printf "\033[31mNo KERNHEAP\033[m\n\n" | |
477 | + printf " The KERNHEAP hardening patchset is available here:\n" | |
478 | + printf " https://www.subreption.com/kernheap/\n\n" | |
479 | + fi | |
480 | +} | |
481 | + | |
482 | +# --- FORTIFY_SOURCE subfunctions (start) --- | |
483 | + | |
484 | +# is FORTIFY_SOURCE supported by libc? | |
485 | +FS_libc_check() { | |
486 | + printf "* FORTIFY_SOURCE support available (libc) : " | |
487 | + | |
488 | + if [ "${#FS_chk_func_libc[@]}" != "0" ] ; then | |
489 | + printf "\033[32mYes\033[m\n" | |
490 | + else | |
491 | + printf "\033[31mNo\033[m\n" | |
492 | + exit 1 | |
493 | + fi | |
494 | +} | |
495 | + | |
496 | +# was the binary compiled with FORTIFY_SOURCE? | |
497 | +FS_binary_check() { | |
498 | + printf "* Binary compiled with FORTIFY_SOURCE support: " | |
499 | + | |
500 | + for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1))) | |
501 | + do | |
502 | + if [[ ${FS_functions[$FS_elem_functions]} =~ _chk ]] ; then | |
503 | + printf "\033[32mYes\033[m\n" | |
504 | + return | |
505 | + fi | |
506 | + done | |
507 | + printf "\033[31mNo\033[m\n" | |
508 | + exit 1 | |
509 | +} | |
510 | + | |
511 | +FS_comparison() { | |
512 | + echo | |
513 | + printf " ------ EXECUTABLE-FILE ------- . -------- LIBC --------\n" | |
514 | + printf " FORTIFY-able library functions | Checked function names\n" | |
515 | + printf " -------------------------------------------------------\n" | |
516 | + | |
517 | + for FS_elem_libc in $(seq 0 $((${#FS_chk_func_libc[@]} - 1))) | |
518 | + do | |
519 | + for FS_elem_functions in $(seq 0 $((${#FS_functions[@]} - 1))) | |
520 | + do | |
521 | + FS_tmp_func=${FS_functions[$FS_elem_functions]} | |
522 | + FS_tmp_libc=${FS_chk_func_libc[$FS_elem_libc]} | |
523 | + | |
524 | + if [[ $FS_tmp_func =~ ^$FS_tmp_libc$ ]] ; then | |
525 | + printf " \033[31m%-30s\033[m | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end | |
526 | + let FS_cnt_total++ | |
527 | + let FS_cnt_unchecked++ | |
528 | + elif [[ $FS_tmp_func =~ ^$FS_tmp_libc(_chk) ]] ; then | |
529 | + printf " \033[32m%-30s\033[m | __%s%s\n" $FS_tmp_func $FS_tmp_libc $FS_end | |
530 | + let FS_cnt_total++ | |
531 | + let FS_cnt_checked++ | |
532 | + fi | |
533 | + | |
534 | + done | |
535 | + done | |
536 | +} | |
537 | + | |
538 | +FS_summary() { | |
539 | + echo | |
540 | + printf "SUMMARY:\n\n" | |
541 | + printf "* Number of checked functions in libc : ${#FS_chk_func_libc[@]}\n" | |
542 | + printf "* Total number of library functions in the executable: ${#FS_functions[@]}\n" | |
543 | + printf "* Number of FORTIFY-able functions in the executable : %s\n" $FS_cnt_total | |
544 | + printf "* Number of checked functions in the executable : \033[32m%s\033[m\n" $FS_cnt_checked | |
545 | + printf "* Number of unchecked functions in the executable : \033[31m%s\033[m\n" $FS_cnt_unchecked | |
546 | + echo | |
547 | +} | |
548 | + | |
549 | +# --- FORTIFY_SOURCE subfunctions (end) --- | |
550 | + | |
551 | +if !(command_exists readelf) ; then | |
552 | + printf "\033[31mWarning: 'readelf' not found! It's required for most checks.\033[m\n\n" | |
553 | + have_readelf=0 | |
554 | +fi | |
555 | + | |
556 | +# parse command-line arguments | |
557 | +case "$1" in | |
558 | + | |
559 | + --version) | |
560 | + version | |
561 | + exit 0 | |
562 | + ;; | |
563 | + | |
564 | + --help) | |
565 | + help | |
566 | + exit 0 | |
567 | + ;; | |
568 | + | |
569 | + --dir) | |
570 | + if [ "$3" = "-v" ] ; then | |
571 | + verbose=true | |
572 | + fi | |
573 | + if [ $have_readelf -eq 0 ] ; then | |
574 | + exit 1 | |
575 | + fi | |
576 | + if [ -z "$2" ] ; then | |
577 | + printf "\033[31mError: Please provide a valid directory.\033[m\n\n" | |
578 | + exit 1 | |
579 | + fi | |
580 | + # remove trailing slashes | |
581 | + tempdir=`echo $2 | sed -e "s/\/*$//"` | |
582 | + if [ ! -d $tempdir ] ; then | |
583 | + printf "\033[31mError: The directory '$tempdir' does not exist.\033[m\n\n" | |
584 | + exit 1 | |
585 | + fi | |
586 | + cd $tempdir | |
587 | + printf "RELRO STACK CANARY NX PIE RPATH RUNPATH FILE\n" | |
588 | + for N in [A-Za-z]*; do | |
589 | + if [ "$N" != "[A-Za-z]*" ]; then | |
590 | + # read permissions? | |
591 | + if [ ! -r $N ]; then | |
592 | + printf "\033[31mError: No read permissions for '$tempdir/$N' (run as root).\033[m\n" | |
593 | + else | |
594 | + # ELF executable? | |
595 | + out=`file $N` | |
596 | + if [[ ! $out =~ ELF ]] ; then | |
597 | + if [ "$verbose" = "true" ] ; then | |
598 | + printf "\033[34m*** Not an ELF file: $tempdir/" | |
599 | + file $N | |
600 | + printf "\033[m" | |
601 | + fi | |
602 | + else | |
603 | + filecheck $N | |
604 | + if [ `find $tempdir/$N \( -perm -004000 -o -perm -002000 \) -type f -print` ]; then | |
605 | + printf "\033[37;41m%s%s\033[m" $2 $N | |
606 | + else | |
607 | + printf "%s%s" $tempdir/ $N | |
608 | + fi | |
609 | + echo | |
610 | + fi | |
611 | + fi | |
612 | + fi | |
613 | + done | |
614 | + exit 0 | |
615 | + ;; | |
616 | + | |
617 | + --file) | |
618 | + if [ $have_readelf -eq 0 ] ; then | |
619 | + exit 1 | |
620 | + fi | |
621 | + if [ -z "$2" ] ; then | |
622 | + printf "\033[31mError: Please provide a valid file.\033[m\n\n" | |
623 | + exit 1 | |
624 | + fi | |
625 | + # does the file exist? | |
626 | + if [ ! -e $2 ] ; then | |
627 | + printf "\033[31mError: The file '$2' does not exist.\033[m\n\n" | |
628 | + exit 1 | |
629 | + fi | |
630 | + # read permissions? | |
631 | + if [ ! -r $2 ] ; then | |
632 | + printf "\033[31mError: No read permissions for '$2' (run as root).\033[m\n\n" | |
633 | + exit 1 | |
634 | + fi | |
635 | + # ELF executable? | |
636 | + out=`file $2` | |
637 | + if [[ ! $out =~ ELF ]] ; then | |
638 | + printf "\033[31mError: Not an ELF file: " | |
639 | + file $2 | |
640 | + printf "\033[m\n" | |
641 | + exit 1 | |
642 | + fi | |
643 | + printf "RELRO STACK CANARY NX PIE RPATH RUNPATH FILE\n" | |
644 | + filecheck $2 | |
645 | + if [ `find $2 \( -perm -004000 -o -perm -002000 \) -type f -print` ] ; then | |
646 | + printf "\033[37;41m%s%s\033[m" $2 $N | |
647 | + else | |
648 | + printf "%s" $2 | |
649 | + fi | |
650 | + echo | |
651 | + exit 0 | |
652 | + ;; | |
653 | + | |
654 | + --proc-all) | |
655 | + if [ $have_readelf -eq 0 ] ; then | |
656 | + exit 1 | |
657 | + fi | |
658 | + cd /proc | |
659 | + printf "* System-wide ASLR" | |
660 | + aslrcheck | |
661 | + printf "* Does the CPU support NX: " | |
662 | + nxcheck | |
663 | + printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" | |
664 | + for N in [1-9]*; do | |
665 | + if [ $N != $$ ] && readlink -q $N/exe > /dev/null; then | |
666 | + printf "%16s" `head -1 $N/status | cut -b 7-` | |
667 | + printf "%7d " $N | |
668 | + proccheck $N | |
669 | + echo | |
670 | + fi | |
671 | + done | |
672 | + if [ ! -e /usr/bin/id ] ; then | |
673 | + printf "\n\033[33mNote: If you are running 'checksec.sh' as an unprivileged user, you\n" | |
674 | + printf " will not see all processes. Please run the script as root.\033[m\n\n" | |
675 | + else | |
676 | + if !(root_privs) ; then | |
677 | + printf "\n\033[33mNote: You are running 'checksec.sh' as an unprivileged user.\n" | |
678 | + printf " Too see all processes, please run the script as root.\033[m\n\n" | |
679 | + fi | |
680 | + fi | |
681 | + exit 0 | |
682 | + ;; | |
683 | + | |
684 | + --proc) | |
685 | + if [ $have_readelf -eq 0 ] ; then | |
686 | + exit 1 | |
687 | + fi | |
688 | + if [ -z "$2" ] ; then | |
689 | + printf "\033[31mError: Please provide a valid process name.\033[m\n\n" | |
690 | + exit 1 | |
691 | + fi | |
692 | + if !(isString "$2") ; then | |
693 | + printf "\033[31mError: Please provide a valid process name.\033[m\n\n" | |
694 | + exit 1 | |
695 | + fi | |
696 | + cd /proc | |
697 | + printf "* System-wide ASLR" | |
698 | + aslrcheck | |
699 | + printf "* Does the CPU support NX: " | |
700 | + nxcheck | |
701 | + printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" | |
702 | + for N in `ps -Ao pid,comm | grep $2 | cut -b1-6`; do | |
703 | + if [ -d $N ] ; then | |
704 | + printf "%16s" `head -1 $N/status | cut -b 7-` | |
705 | + printf "%7d " $N | |
706 | + # read permissions? | |
707 | + if [ ! -r $N/exe ] ; then | |
708 | + if !(root_privs) ; then | |
709 | + printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" | |
710 | + exit 1 | |
711 | + fi | |
712 | + if [ ! `readlink $N/exe` ] ; then | |
713 | + printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" | |
714 | + exit 1 | |
715 | + fi | |
716 | + exit 1 | |
717 | + fi | |
718 | + proccheck $N | |
719 | + echo | |
720 | + fi | |
721 | + done | |
722 | + exit 0 | |
723 | + ;; | |
724 | + | |
725 | + --proc-libs) | |
726 | + if [ $have_readelf -eq 0 ] ; then | |
727 | + exit 1 | |
728 | + fi | |
729 | + if [ -z "$2" ] ; then | |
730 | + printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" | |
731 | + exit 1 | |
732 | + fi | |
733 | + if !(isNumeric "$2") ; then | |
734 | + printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" | |
735 | + exit 1 | |
736 | + fi | |
737 | + cd /proc | |
738 | + printf "* System-wide ASLR" | |
739 | + aslrcheck | |
740 | + printf "* Does the CPU support NX: " | |
741 | + nxcheck | |
742 | + printf "* Process information:\n\n" | |
743 | + printf " COMMAND PID RELRO STACK CANARY NX/PaX PIE\n" | |
744 | + N=$2 | |
745 | + if [ -d $N ] ; then | |
746 | + printf "%16s" `head -1 $N/status | cut -b 7-` | |
747 | + printf "%7d " $N | |
748 | + # read permissions? | |
749 | + if [ ! -r $N/exe ] ; then | |
750 | + if !(root_privs) ; then | |
751 | + printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" | |
752 | + exit 1 | |
753 | + fi | |
754 | + if [ ! `readlink $N/exe` ] ; then | |
755 | + printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" | |
756 | + exit 1 | |
757 | + fi | |
758 | + exit 1 | |
759 | + fi | |
760 | + proccheck $N | |
761 | + echo | |
762 | + libcheck $N | |
763 | + fi | |
764 | + exit 0 | |
765 | + ;; | |
766 | + | |
767 | + --kernel) | |
768 | + cd /proc | |
769 | + printf "* Kernel protection information:\n\n" | |
770 | + kernelcheck | |
771 | + exit 0 | |
772 | + ;; | |
773 | + | |
774 | + --fortify-file) | |
775 | + if [ $have_readelf -eq 0 ] ; then | |
776 | + exit 1 | |
777 | + fi | |
778 | + if [ -z "$2" ] ; then | |
779 | + printf "\033[31mError: Please provide a valid file.\033[m\n\n" | |
780 | + exit 1 | |
781 | + fi | |
782 | + # does the file exist? | |
783 | + if [ ! -e $2 ] ; then | |
784 | + printf "\033[31mError: The file '$2' does not exist.\033[m\n\n" | |
785 | + exit 1 | |
786 | + fi | |
787 | + # read permissions? | |
788 | + if [ ! -r $2 ] ; then | |
789 | + printf "\033[31mError: No read permissions for '$2' (run as root).\033[m\n\n" | |
790 | + exit 1 | |
791 | + fi | |
792 | + # ELF executable? | |
793 | + out=`file $2` | |
794 | + if [[ ! $out =~ ELF ]] ; then | |
795 | + printf "\033[31mError: Not an ELF file: " | |
796 | + file $2 | |
797 | + printf "\033[m\n" | |
798 | + exit 1 | |
799 | + fi | |
800 | + if [ -e /lib/libc.so.6 ] ; then | |
801 | + FS_libc=/lib/libc.so.6 | |
802 | + elif [ -e /lib64/libc.so.6 ] ; then | |
803 | + FS_libc=/lib64/libc.so.6 | |
804 | + elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then | |
805 | + FS_libc=/lib/i386-linux-gnu/libc.so.6 | |
806 | + elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then | |
807 | + FS_libc=/lib/x86_64-linux-gnu/libc.so.6 | |
808 | + else | |
809 | + printf "\033[31mError: libc not found.\033[m\n\n" | |
810 | + exit 1 | |
811 | + fi | |
812 | + | |
813 | + FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') ) | |
814 | + FS_functions=( $(readelf -s $2 | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') ) | |
815 | + | |
816 | + FS_libc_check | |
817 | + FS_binary_check | |
818 | + FS_comparison | |
819 | + FS_summary | |
820 | + | |
821 | + exit 0 | |
822 | + ;; | |
823 | + | |
824 | + --fortify-proc) | |
825 | + if [ $have_readelf -eq 0 ] ; then | |
826 | + exit 1 | |
827 | + fi | |
828 | + if [ -z "$2" ] ; then | |
829 | + printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" | |
830 | + exit 1 | |
831 | + fi | |
832 | + if !(isNumeric "$2") ; then | |
833 | + printf "\033[31mError: Please provide a valid process ID.\033[m\n\n" | |
834 | + exit 1 | |
835 | + fi | |
836 | + cd /proc | |
837 | + N=$2 | |
838 | + if [ -d $N ] ; then | |
839 | + # read permissions? | |
840 | + if [ ! -r $N/exe ] ; then | |
841 | + if !(root_privs) ; then | |
842 | + printf "\033[31mNo read permissions for '/proc/$N/exe' (run as root).\033[m\n\n" | |
843 | + exit 1 | |
844 | + fi | |
845 | + if [ ! `readlink $N/exe` ] ; then | |
846 | + printf "\033[31mPermission denied. Requested process ID belongs to a kernel thread.\033[m\n\n" | |
847 | + exit 1 | |
848 | + fi | |
849 | + exit 1 | |
850 | + fi | |
851 | + if [ -e /lib/libc.so.6 ] ; then | |
852 | + FS_libc=/lib/libc.so.6 | |
853 | + elif [ -e /lib64/libc.so.6 ] ; then | |
854 | + FS_libc=/lib64/libc.so.6 | |
855 | + elif [ -e /lib/i386-linux-gnu/libc.so.6 ] ; then | |
856 | + FS_libc=/lib/i386-linux-gnu/libc.so.6 | |
857 | + elif [ -e /lib/x86_64-linux-gnu/libc.so.6 ] ; then | |
858 | + FS_libc=/lib/x86_64-linux-gnu/libc.so.6 | |
859 | + else | |
860 | + printf "\033[31mError: libc not found.\033[m\n\n" | |
861 | + exit 1 | |
862 | + fi | |
863 | + printf "* Process name (PID) : %s (%d)\n" `head -1 $N/status | cut -b 7-` $N | |
864 | + FS_chk_func_libc=( $(readelf -s $FS_libc | grep _chk@@ | awk '{ print $8 }' | cut -c 3- | sed -e 's/_chk@.*//') ) | |
865 | + FS_functions=( $(readelf -s $2/exe | awk '{ print $8 }' | sed 's/_*//' | sed -e 's/@.*//') ) | |
866 | + | |
867 | + FS_libc_check | |
868 | + FS_binary_check | |
869 | + FS_comparison | |
870 | + FS_summary | |
871 | + fi | |
872 | + exit 0 | |
873 | + ;; | |
874 | + | |
875 | + *) | |
876 | + if [ "$#" != "0" ] ; then | |
877 | + printf "\033[31mError: Unknown option '$1'.\033[m\n\n" | |
878 | + fi | |
879 | + help | |
880 | + exit 1 | |
881 | + ;; | |
882 | +esac |