]>
Commit | Line | Data |
---|---|---|
effd7ca1 TH |
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 |