Advertisement
Guest User

Untitled

a guest
Nov 21st, 2018
163
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 49.98 KB | None | 0 0
  1. #!/bin/sh
  2. # unix-privesc-check - Checks Unix system for simple privilege escalations
  3. # Copyright (C) 2008 pentestmonkey@pentestmonkey.net
  4. # Copyright (C) 2009 timb@nth-dimension.org.uk
  5. #
  6. #
  7. # License
  8. # -------
  9. # This tool may be used for legal purposes only. Users take full responsibility
  10. # for any actions performed using this tool. The author accepts no liability
  11. # for damage caused by this tool. If you do not accept these condition then
  12. # you are prohibited from using this tool.
  13. #
  14. # In all other respects the GPL version 2 applies:
  15. #
  16. # This program is free software; you can redistribute it and/or modify
  17. # it under the terms of the GNU General Public License version 2 as
  18. # published by the Free Software Foundation.
  19. #
  20. # This program is distributed in the hope that it will be useful,
  21. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. # GNU General Public License for more details.
  24. #
  25. # You should have received a copy of the GNU General Public License along
  26. # with this program; if not, write to the Free Software Foundation, Inc.,
  27. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  28. #
  29. # You are encouraged to send comments, improvements or suggestions to
  30. # me at pentestmonkey@pentestmonkey.net
  31. #
  32. #
  33. # Description
  34. # -----------
  35. # Auditing tool to check for weak file permissions and other problems that
  36. # may allow local attackers to escalate privileges.
  37. #
  38. # It is intended to be run by security auditors and penetration testers
  39. # against systems they have been engaged to assess, and also by system
  40. # administrators who want to check for "obvious" misconfigurations. It
  41. # can even be run as a cron job so you can check regularly for misconfigurations
  42. # that might be introduced.
  43. #
  44. # Ensure that you have the appropriate legal permission before running it
  45. # someone else's system.
  46. #
  47. # TODO List
  48. # ---------
  49. # There's still plenty that this script doesn't do...
  50. # - Doesn't work for shell scripts! These appear as "/bin/sh my.sh" in the process listing.
  51. # This script only checks the perms of /bin/sh. Not what we're after. :-(
  52. # - Similarly for perl scripts. Probably python, etc. too.
  53. # - Check /proc/pid/cmdline for absolute path names. Check security of these (e.g. /etc/snmp/snmpd.conf)
  54. # - Check everything in root's path - how to find root's path?
  55. # - /proc/pid/maps, smaps are readable and lists some shared objects. We should check these.
  56. # - We should also check whether libraries are in writable address space
  57. # - AIX/Solaris executable stack
  58. # - Is firewall DMA enabled?
  59. # - Loadable kernel modules?
  60. # - /proc/pid/fd contain symlinks to all open files (but you can't see other people FDs)
  61. # - check for trust relationships in /etc/hosts.equiv
  62. # - NFS imports / exports / automounter
  63. # - Insecure stuff in /etc/fstab (e.g. allowing users to mount file systems)
  64. # - Inspecting people's PATH. tricky. maybe read from /proc/pid/environ, .bashrc, /etc/profile, .bash_profile
  65. # - Check if /etc/init.d/* scripts are readable. Advise user to audit them if they are.
  66. # - .exrc? (partial support added)
  67. # - X11 trusts, apache passwd files, mysql trusts?
  68. # - Daemons configured in an insecure way: tftpd, sadmind, rexd
  69. # - World writable dirs aren't as bad if the sticky bit is set. Check for this before reporting vulns.
  70. # - Maybe do a strings of binaries (and their .so's?)
  71. # - Do a better job of parsing cron lines - search for full paths
  72. # - Maybe LDPATHs from /etc/env.d
  73. # - Check if ldd, ld.so.conf changes have broken this script on non-linux systems.
  74. # - ld.so.conf has an equivelent at least on Solaris
  75. # - Avoid check certain paths e.g. /-/_ clearly isn't a real directory.
  76. # - create some sort of readable report
  77. # - indicate when it's likely a result is a false positive and when it's not.
  78. # - Skip pseudo processes e.g. [usb-storage]
  79. # - File permission on kernel modules
  80. # - Replace calls to echo with a my_echo func. Should be passed a string and an "importance" value:
  81. # - my_echo 1 "This is important and should always be printed out"
  82. # - my_echo 2 "This is less important and should only be printed in verbose mode"
  83. # - We check some files / dirs multiple times. Slow. Can we implement a cache?
  84. # - grep for PRIVATE KEY to find private ssh and ssl keys. Where to grep?
  85. # - check SGID programs
  86. # - Get rid of the awk, command-to-parse-output-from | while read parta partb partc is much better
  87. # - HPUX TCB?
  88. # - caps on processes
  89.  
  90. VERSION="1.6"
  91. SVNVERSION="$Revision$" # Don't change this line. Auto-updated.
  92. SVNVNUM=`echo $SVNVERSION | sed 's/[^0-9]//g'`
  93. if [ -n $SVNVNUM ]; then
  94. VERSION="$VERSION-svn-$SVNVNUM"
  95. fi
  96.  
  97. HOME_DIR_FILES=".exrc .netrc .ssh/id_rsa .ssh/id_dsa .rhosts .shosts .my.cnf .ssh/authorized_keys .bash_history .sh_history .forward"
  98. CONFIG_FILES="/etc/passwd /etc/group /etc/master.passwd /etc/inittab /etc/inetd.conf /etc/xinetd.conf /etc/xinetd.d/* /etc/crontab /etc/fstab /etc/profile /etc/sudoers /etc/hosts.equiv /etc/shosts.equiv"
  99. PGDIRS="/usr/local/pgsql/data ~postgres/postgresql/data ~postgres/data ~pgsql/data ~pgsql/pgsql/data /var/lib/postgresql/data /etc/postgresql/8.2/main /var/lib/pgsql/data"
  100.  
  101. get_owner () {
  102. GET_OWNER_FILE=$1
  103. GET_OWNER_RETURN=`ls -lLd "$GET_OWNER_FILE" | awk '{print $3}'`
  104. }
  105.  
  106. get_group () {
  107. GET_GROUP_FILE=$1
  108. GET_GROUP_RETURN=`ls -lLd "$GET_GROUP_FILE" | awk '{print $4}'`
  109. }
  110.  
  111. usage () {
  112. echo "unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )"
  113. echo
  114. echo "Usage: unix-privesc-check { standard | detailed }"
  115. echo
  116. echo '"standard" mode: Speed-optimised check of lots of security settings.'
  117. echo
  118. echo '"detailed" mode: Same as standard mode, but also checks perms of open file'
  119. echo ' handles and called files (e.g. parsed from shell scripts,'
  120. echo ' linked .so files). This mode is slow and prone to false '
  121. echo ' positives but might help you find more subtle flaws in 3rd'
  122. echo ' party programs.'
  123. echo
  124. echo "This script checks file permissions and other settings that could allow"
  125. echo "local users to escalate privileges."
  126. echo
  127. echo "Use of this script is only permitted on systems which you have been granted"
  128. echo "legal permission to perform a security assessment of. Apart from this "
  129. echo "condition the GPL v2 applies."
  130. echo
  131. echo "Search the output for the word 'WARNING'. If you don't see it then this"
  132. echo "script didn't find any problems."
  133. echo
  134. }
  135.  
  136. banner () {
  137. echo "Starting unix-privesc-check v$VERSION ( http://pentestmonkey.net/tools/unix-privesc-check )"
  138. echo
  139. echo "This script checks file permissions and other settings that could allow"
  140. echo "local users to escalate privileges."
  141. echo
  142. echo "Use of this script is only permitted on systems which you have been granted"
  143. echo "legal permission to perform a security assessment of. Apart from this "
  144. echo "condition the GPL v2 applies."
  145. echo
  146. echo "Search the output below for the word 'WARNING'. If you don't see it then"
  147. echo "this script didn't find any problems."
  148. echo
  149. }
  150.  
  151. MODE=$1
  152.  
  153. if [ ! "$MODE" = "standard" ] && [ ! "$MODE" = "detailed" ]; then
  154. usage
  155. exit 0
  156. fi
  157.  
  158. # Parse any full paths from $1 (config files, progs, dirs).
  159. # Check the permissions on each of these.
  160. check_called_programs () {
  161. CCP_MESSAGE_STACK=$1
  162. CCP_FILE=$2
  163. CCP_USER=$3
  164. CCP_PATH=$4 # optional
  165.  
  166. # Check the perms of the supplied file regardless
  167. # The caller doesn't want to have to call check_perms as well as check_called_programs
  168. check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH"
  169.  
  170. # Skip the slow check if we're in quick mode
  171. if [ "$MODE" = "standard" ]; then
  172. return 0;
  173. fi
  174.  
  175. # Check if file is text or not
  176. IS_TEXT=`file "$CCP_FILE" | grep -i text`
  177. if [ $OS = "aix" ]; then
  178. IS_DYNBIN=`file "$CCP_FILE" | grep -i 'object module'`
  179. else
  180. IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
  181. fi
  182.  
  183. # Process shell scripts (would also work on config files that reference other files)
  184. if [ ! -z "$IS_TEXT" ]; then
  185. # Parse full paths from file - ignoring commented lines
  186. CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
  187. for CALLED_FILE in $CALLED_FILES; do
  188. # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms."
  189. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
  190. done
  191. else
  192. # Process dynamically linked binaries
  193. if [ ! -z "$IS_DYNBIN" ]; then
  194.  
  195. CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' ' | cut -f 1 -d '('`
  196. for CALLED_FILE in $CALLED_FILES; do
  197. check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
  198. done
  199.  
  200. # Strings binary to look for hard-coded config files
  201. # or other programs that might be called.
  202. for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
  203. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "$CCP_USER" "$CCP_PATH"
  204. done
  205. fi
  206. fi
  207. }
  208.  
  209. # Parse any full paths from $1 (config files, progs, dirs).
  210. # Check the permissions on each of these.
  211. check_called_programs_suid_sgid () {
  212. CCP_FILE=$1
  213.  
  214. is_suid $CCP_FILE # sets $IS_SUID_RETURN
  215.  
  216. if [ "$IS_SUID_RETURN" -eq 1 ]; then
  217. check_called_programs_suid $CCP_FILE
  218. fi
  219.  
  220. is_sgid $CCP_FILE # sets $IS_SGID_RETURN
  221.  
  222. if [ "$IS_SGID_RETURN" -eq 1 ]; then
  223. check_called_programs_sgid $CCP_FILE
  224. fi
  225. }
  226.  
  227. # Parse any full paths from $1 (config files, progs, dirs).
  228. # Check the permissions on each of these.
  229. check_called_programs_suid () {
  230. CCP_FILE=$1
  231. CCP_PATH=$2 # optional
  232.  
  233. get_owner $CCP_FILE; CCP_USER=$GET_OWNER_RETURN
  234. CCP_MESSAGE_STACK="$CCP_FILE is SUID $CCP_USER."
  235. LS=`ls -l $CCP_FILE`
  236. echo "Checking SUID-$CCP_USER program $CCP_FILE: $LS"
  237.  
  238. # Don't check perms of executable itself
  239. # check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH"
  240.  
  241. # Check if file is text or not
  242. IS_TEXT=`file "$CCP_FILE" | grep -i text`
  243. IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
  244.  
  245. # Process shell scripts (would also work on config files that reference other files)
  246. if [ ! -z "$IS_TEXT" ]; then
  247. # Skip the slow check if we're in quick mode
  248. if [ "$MODE" = "standard" ]; then
  249. return 0;
  250. fi
  251.  
  252. # Parse full paths from file - ignoring commented lines
  253. CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
  254. for CALLED_FILE in $CALLED_FILES; do
  255. # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms."
  256. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  257. done
  258. else
  259. # Process dynamically linked binaries
  260. if [ ! -z "$IS_DYNBIN" ]; then
  261.  
  262. CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '`
  263. for CALLED_FILE in $CALLED_FILES; do
  264. check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  265. done
  266.  
  267. # Skip the slow check if we're in quick mode
  268. if [ "$MODE" = "standard" ]; then
  269. return 0;
  270. fi
  271.  
  272. # Strings binary to look for hard-coded config files
  273. # or other programs that might be called.
  274. for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
  275. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  276. done
  277. fi
  278. fi
  279. }
  280.  
  281. # Parse any full paths from $1 (config files, progs, dirs).
  282. # Check the permissions on each of these.
  283. check_called_programs_sgid () {
  284. CCP_FILE=$1
  285. CCP_PATH=$2 # optional
  286.  
  287. get_group $CCP_FILE; CCP_GROUP=$GET_GROUP_RETURN
  288. CCP_MESSAGE_STACK="$CCP_FILE is SGID $CCP_GROUP."
  289. LS=`ls -l $CCP_FILE`
  290. echo "Checking SGID-$CCP_GROUP program $CCP_FILE: $LS"
  291.  
  292. # Don't check perms of executable itself
  293. # check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_USER" "$CCP_PATH"
  294.  
  295. # Check if file is text or not
  296. IS_TEXT=`file "$CCP_FILE" | grep -i text`
  297. IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
  298.  
  299. # Process shell scripts (would also work on config files that reference other files)
  300. if [ ! -z "$IS_TEXT" ]; then
  301. # Skip the slow check if we're in quick mode
  302. if [ "$MODE" = "standard" ]; then
  303. return 0;
  304. fi
  305.  
  306. # Parse full paths from file - ignoring commented lines
  307. CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
  308. for CALLED_FILE in $CALLED_FILES; do
  309. # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms."
  310. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  311. done
  312. else
  313. # Process dynamically linked binaries
  314. if [ ! -z "$IS_DYNBIN" ]; then
  315.  
  316. CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '`
  317. for CALLED_FILE in $CALLED_FILES; do
  318. check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  319. done
  320.  
  321. # Skip the slow check if we're in quick mode
  322. if [ "$MODE" = "standard" ]; then
  323. return 0;
  324. fi
  325.  
  326. # Strings binary to look for hard-coded config files
  327. # or other programs that might be called.
  328. for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
  329. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" root "$CCP_PATH"
  330. done
  331. fi
  332. fi
  333. }
  334.  
  335. # Parse any full paths from $1 (config files, progs, dirs).
  336. # Check the permissions on each of these.
  337. check_called_programs_fscaps () {
  338. CCP_FILE=$1
  339. CCP_PATH=$2 # optional
  340.  
  341. CCP_MESSAGE_STACK="$CCP_FILE has fscaps."
  342. LS=`ls -l $CCP_FILE`
  343. echo "Checking fscaps program $CCP_FILE: $LS"
  344.  
  345. # Don't check perms of executable itself
  346. # check_perms "$CCP_MESSAGE_STACK" "$CCP_FILE" "$CCP_PATH"
  347.  
  348. # Check if file is text or not
  349. IS_TEXT=`file "$CCP_FILE" | grep -i text`
  350. IS_DYNBIN=`file "$CCP_FILE" | grep -i 'dynamically linked'`
  351.  
  352. # Process shell scripts (would also work on config files that reference other files)
  353. if [ ! -z "$IS_TEXT" ]; then
  354. # Skip the slow check if we're in quick mode
  355. if [ "$MODE" = "standard" ]; then
  356. return 0;
  357. fi
  358.  
  359. # Parse full paths from file - ignoring commented lines
  360. CALLED_FILES=`grep -v '^#' "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`
  361. for CALLED_FILE in $CALLED_FILES; do
  362. # echo "$CCP_FILE contains a reference to $CALLED_FILE. Checking perms."
  363. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "root" "$CCP_PATH"
  364. done
  365. else
  366. # Process dynamically linked binaries
  367. if [ ! -z "$IS_DYNBIN" ]; then
  368.  
  369. CALLED_FILES=`ldd "$CCP_FILE" 2>/dev/null | grep '/' | sed 's/[^\/]*\//\//' | cut -f 1 -d ' '`
  370. for CALLED_FILE in $CALLED_FILES; do
  371. check_perms "$CCP_MESSAGE_STACK $CCP_FILE uses the library $CALLED_FILE." "$CALLED_FILE" "root" "$CCP_PATH"
  372. done
  373.  
  374. # Skip the slow check if we're in quick mode
  375. if [ "$MODE" = "standard" ]; then
  376. return 0;
  377. fi
  378.  
  379. # Strings binary to look for hard-coded config files
  380. # or other programs that might be called.
  381. for CALLED_FILE in `strings "$CCP_FILE" | sed -e 's/^[^\/]*//' -e 's/["'\'':}$]/\x0a/g' | grep '/' | sed -e 's/[ \*].*//' | grep '^/[a-zA-Z0-9_/-]*$' | sort -u`; do
  382. check_perms "$CCP_MESSAGE_STACK $CCP_FILE contains the string $CALLED_FILE." "$CALLED_FILE" "root" "$CCP_PATH"
  383. done
  384. fi
  385. fi
  386. }
  387.  
  388. # Check if $2 can be changed by users who are not $3
  389. check_perms () {
  390. CP_MESSAGE_STACK=$1
  391. CHECK_PERMS_FILE=$2
  392. CHECK_PERMS_USER=$3
  393. CHECK_PERMS_PATH=$4 # optional
  394.  
  395. if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -d "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ] && [ ! -c "$CHECK_PERMS_FILE" ]; then
  396. CHECK_PERMS_FOUND=0
  397. if [ ! -z "$CHECK_PERMS_PATH" ]; then
  398. # Look for it in the supplied path
  399. for DIR in `echo "$CHECK_PERMS_PATH" | sed 's/:/ /g'`; do
  400. if [ -f "$DIR/$CHECK_PERMS_FILE" ]; then
  401. CHECK_PERMS_FOUND=1
  402. CHECK_PERMS_FILE="$DIR/$CHECK_PERMS_FILE"
  403. break
  404. fi
  405. done
  406. fi
  407.  
  408. #if [ "$CHECK_PERMS_FOUND" = "0" ]; then
  409. # echo "ERROR: File $CHECK_PERMS_FILE doesn't exist. Checking parent path anyway."
  410. # # return 0
  411. # fi
  412. fi
  413.  
  414. C=`echo "$CHECK_PERMS_FILE" | cut -c 1`
  415. if [ ! "$C" = "/" ]; then
  416. echo "ERROR: Can't find absolute path for $CHECK_PERMS_FILE. Skipping."
  417. return 0
  418. fi
  419.  
  420. echo " Checking if anyone except $CHECK_PERMS_USER can change $CHECK_PERMS_FILE"
  421.  
  422. while [ -n "$CHECK_PERMS_FILE" ]; do
  423. perms_secure "$CP_MESSAGE_STACK" $CHECK_PERMS_FILE $CHECK_PERMS_USER
  424. CHECK_PERMS_FILE=`echo $CHECK_PERMS_FILE | sed 's/\/[^\/]*$//'`
  425. done
  426. }
  427.  
  428. # Check if $1 can be read by users who are not $2
  429. check_read_perms () {
  430. CP_MESSAGE_STACK=$1
  431. CHECK_PERMS_FILE=$2
  432. CHECK_PERMS_USER=$3
  433.  
  434. if [ ! -f "$CHECK_PERMS_FILE" ] && [ ! -b "$CHECK_PERMS_FILE" ] && [ ! -c "$CHECK_PERMS_FILE" ]; then
  435. echo "ERROR: File $CHECK_PERMS_FILE doesn't exist"
  436. return 0
  437. fi
  438.  
  439. echo " Checking if anyone except $CHECK_PERMS_USER can read file $CHECK_PERMS_FILE"
  440.  
  441. perms_secure_read "$CP_MESSAGE_STACK" "$CHECK_PERMS_FILE" "$CHECK_PERMS_USER"
  442. }
  443.  
  444. perms_secure_read () {
  445. PS_MESSAGE_STACK=$1
  446. PERMS_SECURE_FILE=$2
  447. PERMS_SECURE_USER=$3
  448.  
  449. if [ ! -b "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -d "$PERMS_SECURE_FILE" ] && [ ! -c "$PERMS_SECURE_FILE" ]; then
  450. echo "ERROR: No such file or directory: $PERMS_SECURE_FILE. Skipping."
  451. return 0
  452. fi
  453.  
  454. # Check if owner is different (but ignore root ownership, that's OK)
  455. only_user_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
  456.  
  457. # Check group read perm (but ignore root group, that's OK)
  458. group_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
  459.  
  460. # Check world read perm
  461. world_can_read "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE
  462. }
  463.  
  464. perms_secure () {
  465. PS_MESSAGE_STACK=$1
  466. PERMS_SECURE_FILE=$2
  467. PERMS_SECURE_USER=$3
  468.  
  469. if [ ! -d "$PERMS_SECURE_FILE" ] && [ ! -f "$PERMS_SECURE_FILE" ] && [ ! -b "$PERMS_SECURE_FILE" ] && [ ! -c "$PERMS_SECURE_FILE" ]; then
  470. # echo "ERROR: No such file or directory: $PERMS_SECURE_FILE. Skipping."
  471. return 0
  472. fi
  473.  
  474. # Check if owner is different (but ignore root ownership, that's OK)
  475. only_user_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
  476.  
  477. # Check group write perm (but ignore root group, that's OK)
  478. group_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE $PERMS_SECURE_USER
  479.  
  480. # Check world write perm
  481. world_can_write "$PS_MESSAGE_STACK" $PERMS_SECURE_FILE
  482. }
  483.  
  484. only_user_can_write () {
  485. O_MESSAGE_STACK=$1
  486. O_FILE=$2
  487. O_USER=$3
  488.  
  489. # We just need to check the owner really as the owner
  490. # can always grant themselves write access
  491. get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN
  492. if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then
  493. echo "[UPC001] WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can write to $O_FILE"
  494. fi
  495. }
  496.  
  497. group_can_write () {
  498. O_MESSAGE_STACK=$1
  499. O_FILE=$2
  500. O_USER=$3 # ignore group write access $3 is only member of group
  501.  
  502. get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN
  503. P=`ls -lLd $O_FILE | cut -c 6`
  504. if [ "$P" = "w" ] && [ ! "$O_GROUP" = "root" ]; then
  505. # check the group actually has some members other than $O_USER
  506. group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0
  507. if [ "$OTHER_MEMBERS" = "1" ]; then
  508. echo "[UPC002] WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can write to $O_FILE"
  509. fi
  510. fi
  511. }
  512.  
  513. is_suid () {
  514. O_FILE=$1
  515.  
  516. P=`ls -lLd $O_FILE | cut -c 4`
  517. if [ "$P" = "s" ]; then
  518. IS_SUID_RETURN=1
  519. else
  520. IS_SUID_RETURN=0
  521. fi
  522. }
  523.  
  524. is_sgid () {
  525. O_FILE=$1
  526.  
  527. P=`ls -lLd $O_FILE | cut -c 7`
  528. if [ "$P" = "s" ]; then
  529. IS_SGID_RETURN=1
  530. else
  531. IS_SGID_RETURN=0
  532. fi
  533. }
  534.  
  535. group_has_other_members () {
  536. G_GROUP=$1
  537. G_USER=$2
  538.  
  539. # If LDAP/NIS is being used this script can't check group memberships
  540. # we therefore assume the worst.
  541. if [ "$EXT_AUTH" = 1 ]; then
  542. OTHER_MEMBERS=1
  543. return 1
  544. fi
  545.  
  546. GROUP_LINE=`grep "^$G_GROUP:" /etc/group`
  547. MEMBERS=`echo "$GROUP_LINE" | cut -f 4 -d : | sed 's/,/ /g'`
  548.  
  549. GID=`echo "$GROUP_LINE" | cut -f 3 -d :`
  550. EXTRA_MEMBERS=`grep "^[^:]*:[^:]*:[0-9]*:$GID:" /etc/passwd | cut -f 1 -d : | xargs echo`
  551.  
  552. for M in $MEMBERS; do
  553. if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then
  554. OTHER_MEMBERS=1
  555. return 1
  556. fi
  557. done
  558.  
  559. for M in $EXTRA_MEMBERS; do
  560. if [ ! "$M" = "$G_USER" ] && [ ! "$M" = "root" ]; then
  561. OTHER_MEMBERS=1
  562. return 1
  563. fi
  564. done
  565.  
  566. OTHER_MEMBERS=0
  567. return 0
  568. }
  569.  
  570. world_can_write () {
  571. O_MESSAGE_STACK=$1
  572. O_FILE=$2
  573.  
  574. P=`ls -lLd $O_FILE | cut -c 9`
  575. S=`ls -lLd $O_FILE | cut -c 10`
  576.  
  577. if [ "$P" = "w" ]; then
  578. if [ "$S" = "t" ]; then
  579. echo "[UPC003] WARNING: $O_MESSAGE_STACK World write is set for $O_FILE (but sticky bit set)"
  580. else
  581. echo "[UPC004] WARNING: $O_MESSAGE_STACK World write is set for $O_FILE"
  582. fi
  583. fi
  584. }
  585.  
  586. only_user_can_read () {
  587. O_MESSAGE_STACK=$1
  588. O_FILE=$2
  589. O_USER=$3
  590.  
  591. # We just need to check the owner really as the owner
  592. # can always grant themselves read access
  593. get_owner $O_FILE; O_FILE_USER=$GET_OWNER_RETURN
  594. if [ ! "$O_USER" = "$O_FILE_USER" ] && [ ! "$O_FILE_USER" = "root" ]; then
  595. echo "[UPC005] WARNING: $O_MESSAGE_STACK The user $O_FILE_USER can read $O_FILE"
  596. fi
  597. }
  598.  
  599. group_can_read () {
  600. O_MESSAGE_STACK=$1
  601. O_FILE=$2
  602. O_USER=$3
  603.  
  604. get_group $O_FILE; O_FILE_GROUP=$GET_GROUP_RETURN
  605. P=`ls -lLd $O_FILE | cut -c 5`
  606. if [ "$P" = "r" ] && [ ! "$O_GROUP" = "root" ]; then
  607. # check the group actually has some members other than $O_USER
  608. group_has_other_members "$O_FILE_GROUP" "$O_USER"; # sets OTHER_MEMBERS to 1 or 0
  609. if [ "$OTHER_MEMBERS" = "1" ]; then
  610. echo "[UPC006] WARNING: $O_MESSAGE_STACK The group $O_FILE_GROUP can read $O_FILE"
  611. fi
  612. fi
  613. }
  614.  
  615. world_can_read () {
  616. O_MESSAGE_STACK=$1
  617. O_FILE=$2
  618.  
  619. P=`ls -lLd $O_FILE | cut -c 8`
  620.  
  621. if [ "$P" = "w" ]; then
  622. echo "[UPC007] WARNING: $O_MESSAGE_STACK World read is set for $O_FILE"
  623. fi
  624. }
  625.  
  626. section () {
  627. echo
  628. echo '############################################'
  629. echo $1
  630. echo '############################################'
  631. }
  632.  
  633. # Guess OS
  634. if [ -x /usr/bin/showrev ]; then
  635. OS="solaris"
  636. SHADOW="/etc/shadow"
  637. elif [ -x /usr/sbin/sam -o -x /usr/bin/sam ]; then
  638. OS="hpux"
  639. SHADOW="/etc/shadow"
  640. elif [ -f /etc/master.passwd ]; then
  641. OS="bsd"
  642. SHADOW="/etc/master.passwd"
  643. elif [ -f /etc/security/user ]; then
  644. OS="aix"
  645. SHADOW="/etc/security/passwd"
  646. else
  647. OS="linux"
  648. SHADOW="/etc/shadow"
  649. fi
  650. echo "Assuming the OS is: $OS"
  651. CONFIG_FILES="$CONFIG_FILES $SHADOW"
  652.  
  653. # Set path so we can access usual directories. HPUX and some linuxes don't have sbin in the path.
  654. PATH=$PATH:/usr/bin:/bin:/sbin:/usr/sbin; export PATH
  655.  
  656. # Check dependent programs are installed
  657. # Assume "which" is installed!
  658. PROGS="ls awk grep cat mount xargs file ldd strings"
  659. for PROG in $PROGS; do
  660. which $PROG 2>&1 > /dev/null
  661. if [ ! $? = "0" ]; then
  662. echo "ERROR: Dependend program '$PROG' is mising. Can't run. Sorry!"
  663. exit 1
  664. fi
  665. done
  666.  
  667. banner
  668.  
  669. section "Recording hostname"
  670. hostname
  671.  
  672. section "Recording uname"
  673. uname -a
  674.  
  675. section "Recording Interface IP addresses"
  676. if [ "$OS" = "hpux" ]; then
  677. for IFACE in `lanscan | grep x | awk '{print $5}' 2>/dev/null`; do
  678. ifconfig $IFACE 2>/dev/null
  679. done
  680. else
  681. ifconfig -a
  682. fi
  683.  
  684. section "Checking if external authentication is allowed in /etc/passwd"
  685. FLAG=`grep '^+:' /etc/passwd`
  686. if [ -n "$FLAG" ]; then
  687. echo "[UPC008] WARNING: /etc/passwd allows external authentcation:"
  688. grep '^+' /etc/passwd
  689. EXT_AUTH=1
  690. else
  691. echo "No +:... line found in /etc/passwd"
  692. fi
  693.  
  694. section "Checking nsswitch.conf/netsvc.conf for addition authentication methods"
  695. if [ "$OS" = "aix" ]; then
  696. if [ -r "/etc/netsvc.conf" ]; then
  697. # ldap_nis Uses LDAP NIS services for resolving names
  698. # nis4 Uses NIS services for resolving only IPv4 addresses
  699. # nis6 Uses NIS services for resolving only IPv6 addresses
  700. # nis+4 Uses NIS plus services for resolving only IPv4 addresses
  701. # nis+6 Uses NIS plus services for resolving only IPv6 addresses
  702. # ldap4 Uses LDAP services for resolving only IPv4 addresses
  703. # ldap6 Uses LDAP services for resolving only IPv6 addresses
  704. # ldap_nis4 Uses NIS LDAP services for resolving only IPv4 addresses
  705. # ldap_nis6 Uses NIS LDAP services for resolving only IPv6 addresses
  706. # ldap Uses LDAP services for resolving names
  707. NIS=`grep '^host' /etc/netsvc.conf | grep 'nis'`
  708. if [ -n "$NIS" ]; then
  709. echo "[UPC009] WARNING: NIS is used for authentication on this system"
  710. EXT_AUTH=1
  711. fi
  712. LDAP=`grep '^host' /etc/netsvc.conf | grep 'ldap'`
  713. if [ -n "$LDAP" ]; then
  714. echo "[UPC010] WARNING: LDAP is used for authentication on this system"
  715. EXT_AUTH=1
  716. fi
  717. else
  718. echo "ERROR: File /etc/netsvc.conf isn't readable. Skipping checks."
  719. fi
  720. else
  721. if [ -r "/etc/nsswitch.conf" ]; then
  722. NIS=`grep '^passwd' /etc/nsswitch.conf | grep 'nis'`
  723. if [ -n "$NIS" ]; then
  724. echo "[UPC011] WARNING: NIS is used for authentication on this system"
  725. EXT_AUTH=1
  726. fi
  727. LDAP=`grep '^passwd' /etc/nsswitch.conf | grep 'ldap'`
  728. if [ -n "$LDAP" ]; then
  729. echo "[UPC012] WARNING: LDAP is used for authentication on this system"
  730. EXT_AUTH=1
  731. fi
  732.  
  733. if [ -z "$NIS" ] && [ -z "$LDAP" ]; then
  734. echo "Neither LDAP nor NIS are used for authentication"
  735. fi
  736. else
  737. echo "ERROR: File /etc/nsswitch.conf isn't readable. Skipping checks."
  738. fi
  739. fi
  740.  
  741. # Check important config files aren't writable
  742. section "Checking for writable config files"
  743. for FILE in $CONFIG_FILES; do
  744. if [ -f "$FILE" ]; then
  745. check_perms "$FILE is a critical config file." "$FILE" root
  746. fi
  747. done
  748.  
  749. section "Checking if $SHADOW is readable"
  750. check_read_perms "$SHADOW holds authentication data" $SHADOW root
  751.  
  752. section "Checking if $SHADOW is writable"
  753. check_perms "$SHADOW can be written to" $SHADOW root
  754.  
  755. section "Checking if /etc/passwd is writable"
  756. check_perms "/etc/passwd can be written to" /etc/passwd root
  757.  
  758. section "Checking for password hashes in /etc/passwd"
  759. FLAG=`grep -v '^[^:]*:[!x\*]*:' /etc/passwd | grep -v '^#'`
  760. if [ -n "$FLAG" ]; then
  761. echo "[UPC013] WARNING: There seem to be some password hashes in /etc/passwd"
  762. grep -v '^[^:]*:[!x\*]*:' /etc/passwd | grep -v '^#'
  763. EXT_AUTH=1
  764. else
  765. echo "No password hashes found in /etc/passwd"
  766. fi
  767.  
  768. section "Checking account settings"
  769. # Check for something nasty like r00t::0:0::/:/bin/sh in /etc/passwd
  770. # We only need read access to /etc/passwd to be able to check this.
  771. if [ -r "/etc/passwd" ]; then
  772. OPEN=`grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":"`
  773. if [ -n "$OPEN" ]; then
  774. echo "[UPC014] WARNING: The following accounts have no password:"
  775. grep "^[^:][^:]*::" /etc/passwd | cut -f 1 -d ":"
  776. fi
  777. fi
  778. if [ -r "$SHADOW" ]; then
  779. echo "Checking for accounts with no passwords"
  780. if [ "$OS" = "linux" ]; then
  781. passwd -S -a | while read LINE
  782. do
  783. USER=`echo "$LINE" | awk '{print $1}'`
  784. STATUS=`echo "$LINE" | awk '{print $2}'`
  785. if [ "$STATUS" = "NP" ]; then
  786. echo "[UPC015] WARNING: User $USER doesn't have a password"
  787. fi
  788. done
  789. elif [ "$OS" = "solaris" ]; then
  790. passwd -s -a | while read LINE
  791. do
  792. USER=`echo "$LINE" | awk '{print $1}'`
  793. STATUS=`echo "$LINE" | awk '{print $2}'`
  794. if [ "$STATUS" = "NP" ]; then
  795. echo "[UPC016] WARNING: User $USER doesn't have a password"
  796. fi
  797. done
  798. fi
  799. else
  800. echo "File $SHADOW isn't readable. Skipping some checks."
  801. fi
  802.  
  803. section "Checking library directories from /etc/ld.so.conf"
  804. if [ -f "/etc/ld.so.conf" ] && [ -r "/etc/ld.so.conf" ]; then
  805. for DIR in `grep '^/' /etc/ld.so.conf`; do
  806. check_perms "$DIR is in /etc/ld.so.conf." $DIR root
  807. done
  808.  
  809. #FILES=`grep '^include' /etc/ld.so.conf | sed 's/^include *//'`
  810. #if [ ! -z "$FILES" ]; then
  811. # for DIR in `echo $FILES | xargs cat | sort -u`; do
  812. # done
  813. #fi
  814. else
  815. echo "File /etc/ld.so.conf not present. Skipping checks."
  816. fi
  817.  
  818. # Check sudoers if we have permission - needs root normally
  819. section "Checking sudo configuration"
  820. if [ -f "/etc/sudoers" ] && [ -r "/etc/sudoers" ]; then
  821. echo -----------------
  822. echo "Checking if sudo is configured"
  823. SUDO_USERS=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep -v '^[ \t]*Default' | grep =`
  824. if [ ! -z "$SUDO_USERS" ]; then
  825. echo "[UPC017] WARNING: Sudo is configured. Manually check nothing unsafe is allowed:"
  826. grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep = | grep -v '^[ \t]*Default'
  827. fi
  828.  
  829. echo -----------------
  830. echo "Checking sudo users need a password"
  831. SUDO_NOPASSWD=`grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD`
  832. if [ ! -z "$SUDO_NOPASSWD" ]; then
  833. echo "[UPC018] WARNING: Some users can use sudo without a password:"
  834. grep -v '^#' /etc/sudoers | grep -v '^[ \t]*$' | grep NOPASSWD
  835. fi
  836. else
  837. echo "File /etc/sudoers not present. Skipping checks."
  838. fi
  839.  
  840. section "Checking permissions on swap file(s)"
  841. if [ "$OS" = "hpux" ]; then
  842. for SWAP in `swapinfo| grep -v '^dev' | awk '{print $9}'`; do
  843. check_perms "$SWAP is used for swap space." $SWAP root
  844. check_read_perms "$SWAP is used for swap space." $SWAP root
  845. done
  846. else
  847. if [ "$OS" != "aix" ]; then
  848. for SWAP in `swapon -s | grep -v '^Filename' | cut -f 1 -d ' '`; do
  849. check_perms "$SWAP is used for swap space." $SWAP root
  850. check_read_perms "$SWAP is used for swap space." $SWAP root
  851. done
  852. fi
  853. fi
  854.  
  855. section "Checking programs run from inittab"
  856. if [ -f "/etc/inittab" ] && [ -r "/etc/inittab" ]; then
  857. for FILE in `cat /etc/inittab | grep : | grep -v '^#' | cut -f 4 -d : | grep '/' | cut -f 1 -d ' ' | sort -u`; do
  858. check_called_programs "$FILE is run from /etc/inittab as root." $FILE root
  859. done
  860. else
  861. echo "File /etc/inittab not present. Skipping checks."
  862. fi
  863.  
  864. section "Checking postgres trust relationships"
  865. for DIR in $PGDIRS; do
  866. if [ -d "$DIR" ] && [ -r "$DIR/pg_hba.conf" ]; then
  867. grep -v '^#' "$DIR/pg_hba.conf" | grep -v '^[ \t]*$' | while read LINE
  868. do
  869. AUTH=`echo "$LINE" | awk '{print $NF}'`
  870. if [ "$AUTH" = "trust" ]; then
  871. PGTRUST=1
  872. echo "[UPC019] WARNING: Postgres trust configured in $DIR/pg_hba.conf: $LINE"
  873. fi
  874. done
  875. fi
  876. done
  877.  
  878. PGVER1=`psql -w -U postgres template1 -c 'select version()' 2>/dev/null | grep version`
  879.  
  880. if [ -n "$PGVER1" ]; then
  881. PGTRUST=1
  882. echo "[UPC020] WARNING: Can connect to local postgres database as \"postgres\" without a password"
  883. fi
  884.  
  885. PGVER2=`psql -w -U pgsql template1 -c 'select version()' 2>/dev/null | grep version`
  886.  
  887. if [ -n "$PGVER2" ]; then
  888. PGTRUST=1
  889. echo "[UPC021] WARNING: Can connect to local postgres database as \"pgsql\" without a password"
  890. fi
  891.  
  892. if [ -z "$PGTRUST" ]; then
  893. echo "No postgres trusts detected"
  894. fi
  895.  
  896. # Check device files for mounted file systems are secure
  897. # cat /proc/mounts | while read LINE # Doesn't work so well when LVM is used - need to be root
  898. section "Checking permissions on device files for mounted partitions"
  899. if [ "$OS" = "linux" ]; then
  900. mount | while read LINE
  901. do
  902. DEVICE=`echo "$LINE" | awk '{print $1}'`
  903. FS=`echo "$LINE" | awk '{print $5}'`
  904. if [ "$FS" = "ext2" ] || [ "$FS" = "ext3" ] ||[ "$FS" = "reiserfs" ]; then
  905. echo "Checking device $DEVICE"
  906. check_perms "$DEVICE is a mounted file system." $DEVICE root
  907. fi
  908. done
  909. elif [ "$OS" = "bsd" ]; then
  910. mount | grep ufs | while read LINE
  911. do
  912. DEVICE=`echo "$LINE" | awk '{print $1}'`
  913. echo "Checking device $DEVICE"
  914. check_perms "$DEVICE is a mounted file system." $DEVICE root
  915. done
  916. elif [ "$OS" = "solaris" ]; then
  917. mount | grep xattr | while read LINE
  918. do
  919. DEVICE=`echo "$LINE" | awk '{print $3}'`
  920. if [ ! "$DEVICE" = "swap" ]; then
  921. echo "Checking device $DEVICE"
  922. check_perms "$DEVICE is a mounted file system." $DEVICE root
  923. fi
  924. done
  925.  
  926. NFS=`mount -v | grep -i ' nfs '`
  927. if [ -n "$NFS" ]; then
  928. echo "[UPC022] WARNING: This system is an NFS client. Check for nosuid and nodev options."
  929. mount -v | grep -i NFS
  930. fi
  931. elif [ "$OS" = "hpux" ]; then
  932. mount | while read LINE
  933. do
  934. DEVICE=`echo "$LINE" | awk '{print $3}'`
  935. C=`echo $DEVICE | cut -c 1`
  936. if [ "$C" = "/" ]; then
  937. echo "Checking device $DEVICE"
  938. check_perms "$DEVICE is a mounted file system." $DEVICE root
  939. fi
  940. done
  941.  
  942. NFS=`mount | grep NFS`
  943. if [ -n "$NFS" ]; then
  944. echo "[UPC022] WARNING: This system is an NFS client. Check for nosuid and nodev options."
  945. mount | grep NFS
  946. fi
  947. elif [ "$OS" = "aix" ]; then
  948. mount | grep jfs2 | while read DEVICE LINE
  949. do
  950. echo "Checking device $DEVICE"
  951. check_perms "$DEVICE is a mounted file system." $DEVICE root
  952. done
  953. fi
  954.  
  955. # Check cron jobs if they're readable
  956. # TODO check that cron is actually running
  957. section "Checking cron job programs aren't writable (/etc/crontab)"
  958. CRONDIRS=""
  959. if [ -f "/etc/crontab" ] && [ -r "/etc/crontab" ]; then
  960. MYPATH=`grep '^PATH=' /etc/crontab | cut -f 2 -d = `
  961. echo Crontab path is $MYPATH
  962.  
  963. # Check if /etc/cron.(hourly|daily|weekly|monthly) are being used
  964. CRONDIRS=`grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-crons`
  965.  
  966. # Process run-parts
  967. grep -v '^#' /etc/crontab | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | grep run-parts | while read LINE
  968. do
  969. echo "Processing crontab run-parts entry: $LINE"
  970. USER=`echo "$LINE" | awk '{print $6}'`
  971. DIR=`echo "$LINE" | sed 's/.*run-parts[^()&|;\/]*\(\/[^ ]*\).*/\1/'`
  972. check_perms "$DIR holds cron jobs which are run as $USER." "$DIR" "$USER"
  973. if [ -d "$DIR" ]; then
  974. echo " Checking directory: $DIR"
  975. for FILE in $DIR/*; do
  976. FILENAME=`echo "$FILE" | sed 's/.*\///'`
  977. if [ "$FILENAME" = "*" ]; then
  978. echo " No files in this directory."
  979. continue
  980. fi
  981. check_called_programs "$FILE is run by cron as $USER." "$FILE" "$USER"
  982. done
  983. fi
  984. done
  985.  
  986. # TODO bsd'd periodic:
  987. # 1 3 * * * root periodic daily
  988. # 15 4 * * 6 root periodic weekly
  989. # 30 5 1 * * root periodic monthly
  990.  
  991. grep -v '^#' /etc/crontab | grep -v '^[ ]*$' | grep '[ ][^ ][^ ]*[ ][ ]*' | while read LINE
  992. do
  993. echo "Processing crontab entry: $LINE"
  994. USER=`echo "$LINE" | awk '{print $6}'`
  995. PROG=`echo "$LINE" | sed 's/(//' | awk '{print $7}'`
  996. check_called_programs "$PROG is run from crontab as $USER." $PROG $USER $MYPATH
  997. done
  998. else
  999. echo "File /etc/crontab not present. Skipping checks."
  1000. fi
  1001.  
  1002. # Do this if run-crons is run from /etc/crontab
  1003. if [ -n "$CRONDIRS" ]; then
  1004. USER=`echo "$CRONDIRS" | awk '{print $6}'`
  1005. section "Checking /etc/cron.(hourly|daily|weekly|monthly)"
  1006. for DIR in hourly daily weekly monthly; do
  1007. if [ -d "/etc/cron.$DIR" ]; then
  1008. echo " Checking directory: /etc/cron.$DIR"
  1009. for FILE in /etc/cron.$DIR/*; do
  1010. FILENAME=`echo "$FILE" | sed 's/.*\///'`
  1011. if [ "$FILENAME" = "*" ]; then
  1012. echo "No files in this directory."
  1013. continue
  1014. fi
  1015. check_called_programs "$FILE is run via cron as $USER." "$FILE" $USER
  1016. done
  1017. fi
  1018. done
  1019. fi
  1020.  
  1021. section "Checking cron job programs aren't writable (/var/spool/cron/crontabs)"
  1022. if [ -d "/var/spool/cron/crontabs" ]; then
  1023. for FILE in /var/spool/cron/crontabs/*; do
  1024. USER=`echo "$FILE" | sed 's/^.*\///'`
  1025. if [ "$USER" = "*" ]; then
  1026. echo "No user crontabs found in /var/spool/cron/crontabs. Skipping checks."
  1027. continue
  1028. fi
  1029. echo "Processing crontab for $USER: $FILE"
  1030. if [ -r "$FILE" ]; then
  1031. MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = `
  1032. if [ -n "$MYPATH" ]; then
  1033. echo Crontab path is $MYPATH
  1034. fi
  1035. grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE
  1036. do
  1037. echo "Processing crontab entry: $LINE"
  1038. PROG=`echo "$LINE" | sed 's/(//' | awk '{print $6}'`
  1039. check_called_programs "$PROG is run via cron as $USER." "$PROG" $USER
  1040. done
  1041. else
  1042. echo "ERROR: Can't read file $FILE"
  1043. fi
  1044. done
  1045. else
  1046. echo "Directory /var/spool/cron/crontabs is not present. Skipping checks."
  1047. fi
  1048.  
  1049. section "Checking cron job programs aren't writable (/var/spool/cron/tabs)"
  1050. if [ -d "/var/spool/cron/tabs" ]; then
  1051. for FILE in /var/spool/cron/tabs/*; do
  1052. USER=`echo "$FILE" | sed 's/^.*\///'`
  1053. if [ "$USER" = "*" ]; then
  1054. echo "No user crontabs found in /var/spool/cron/crontabs. Skipping checks."
  1055. continue
  1056. fi
  1057. echo "Processing crontab for $USER: $FILE"
  1058. if [ -r "$FILE" ]; then
  1059. MYPATH=`grep '^PATH=' "$FILE" | cut -f 2 -d = `
  1060. if [ -n "$MYPATH" ]; then
  1061. echo Crontab path is $MYPATH
  1062. fi
  1063. grep -v '^#' "$FILE" | grep -v '^[ \t]*$' | grep '[ \t][^ \t][^ \t]*[ \t][ \t]*' | while read LINE
  1064. do
  1065. echo "Processing crontab entry: $LINE"
  1066. PROG=`echo "$LINE" | sed 's/(//' | awk '{print $6}'`
  1067. check_called_programs "$PROG is run from cron as $USER." $PROG $USER $MYPATH
  1068. done
  1069. else
  1070. echo "ERROR: Can't read file $FILE"
  1071. fi
  1072. done
  1073. else
  1074. echo "Directory /var/spool/cron/tabs is not present. Skipping checks."
  1075. fi
  1076.  
  1077. # Check programs run from /etc/inetd.conf have secure permissions
  1078. # TODO: check inetd is actually running
  1079. section "Checking inetd programs aren't writable"
  1080. if [ -f /etc/inetd.conf ] && [ -r /etc/inetd.conf ]; then
  1081. grep -v '^#' /etc/inetd.conf | grep -v '^[ \t]*$' | while read LINE
  1082. do
  1083. USER=`echo $LINE | awk '{print $5}'`
  1084. PROG=`echo $LINE | awk '{print $6}'` # could be tcpwappers ...
  1085. PROG2=`echo $LINE | awk '{print $7}'` # ... and this is the real prog
  1086. if [ -z "$PROG" ] || [ "$PROG" = "internal" ]; then
  1087. # Not calling an external program
  1088. continue
  1089. fi
  1090. echo Processing inetd line: $LINE
  1091. if [ -f "$PROG" ]; then
  1092. check_called_programs "$PROG is run from inetd as $USER." $PROG $USER
  1093. fi
  1094. if [ -f "$PROG2" ]; then
  1095. check_called_programs "$PROG is run from inetd as $USER." $PROG2 $USER
  1096. fi
  1097. done
  1098. else
  1099. echo "File /etc/inetd.conf not present. Skipping checks."
  1100. fi
  1101.  
  1102. # Check programs run from /etc/xinetd.d/*
  1103. # TODO: check xinetd is actually running
  1104. section "Checking xinetd programs aren't writeable"
  1105. if [ -d /etc/xinetd.d ]; then
  1106. for FILE in `grep 'disable[ \t]*=[ \t]*no' /etc/xinetd.d/* | cut -f 1 -d :`; do
  1107. echo Processing xinetd service file: $FILE
  1108. PROG=`grep '^[ \t]*server[ \t]*=[ \t]*' $FILE | sed 's/.*server.*=[ \t]*//'`
  1109. USER=`grep '^[ \t]*user[ \t]*=[ \t]*' $FILE | sed 's/.*user.*=[ \t]*//'`
  1110. check_called_programs "$PROG is run from xinetd as $USER." $PROG $USER
  1111. done
  1112. else
  1113. echo "Directory /etc/xinetd.d not present. Skipping checks."
  1114. fi
  1115.  
  1116. # Check for writable home directories
  1117. section "Checking home directories aren't writable"
  1118. cat /etc/passwd | grep -v '^#' | while read LINE
  1119. do
  1120. echo Processing /etc/passwd line: $LINE
  1121. USER=`echo $LINE | cut -f 1 -d :`
  1122. DIR=`echo $LINE | cut -f 6 -d :`
  1123. SHELL=`echo $LINE | cut -f 7 -d :`
  1124. if [ "$SHELL" = "/sbin/nologin" ] || [ "$SHELL" = "/bin/false" ]; then
  1125. echo " Skipping user $USER. They don't have a shell."
  1126. else
  1127. if [ "$DIR" = "/dev/null" ]; then
  1128. echo " Skipping /dev/null home directory"
  1129. else
  1130. check_perms "$DIR is the home directory of $USER." $DIR $USER
  1131. fi
  1132. fi
  1133. done
  1134.  
  1135. # Check for readable files in home directories
  1136. section "Checking for readable sensitive files in home directories"
  1137. cat /etc/passwd | while read LINE
  1138. do
  1139. USER=`echo $LINE | cut -f 1 -d :`
  1140. DIR=`echo $LINE | cut -f 6 -d :`
  1141. SHELL=`echo $LINE | cut -f 7 -d :`
  1142. for FILE in $HOME_DIR_FILES; do
  1143. if [ -f "$DIR/$FILE" ]; then
  1144. check_read_perms "$DIR/$FILE is in the home directory of $USER." "$DIR/$FILE" $USER
  1145. fi
  1146. done
  1147. done
  1148.  
  1149. section "Checking SUID/SGID programs"
  1150. if [ "$MODE" = "detailed" ]; then
  1151. for FILE in `find / -type f -perm -04000 -o -type f -perm -02000 2>/dev/null`; do
  1152. check_called_programs_suid_sgid $FILE
  1153. SUIDDCRIPT=`file $FILE | grep script`
  1154. if [ -n "$SUIDSCRIPT" ]; then
  1155. echo "[UPC023] WARNING: SetUID/SetGID shell script, may be vulnerable to race attacks"
  1156. fi
  1157. done
  1158. else
  1159. echo "Skipping checks of SUID/SGID programs (it's slow!). Run again in 'detailed' mode."
  1160. fi
  1161.  
  1162. section "Checking fscaps programs"
  1163. if [ "$OS" = "linux" -a -x /sbin/getcap ]; then
  1164. if [ "$MODE" = "detailed" ]; then
  1165. for FILE in `find / -type f -perm +0011 -exec /sbin/getcap {} \; 2>/dev/null | grep "=" | awk '{print $1}'`; do
  1166. /sbin/getcap $FILE
  1167. check_called_programs_fscaps $FILE
  1168. FSCAPSSCRIPT=`file $FILE | grep script`
  1169. if [ -n "$FSCAPSSCRIPT" ]; then
  1170. echo "[UPC043] WARNING: fscaps shell script, may be vulnerable to race attacks"
  1171. fi
  1172. done
  1173. else
  1174. echo "Skipping checks of fscaps programs (it's slow!). Run again in 'detailed' mode."
  1175. fi
  1176. fi
  1177.  
  1178. # Check for cleartext subversion passwords
  1179. section "Checking for cleartext subversion passwords in home directories"
  1180. for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do
  1181. if [ -d "$HOMEDIR/.subversion/auth/svn.simple" ]; then
  1182. for FILE in $HOMEDIR/.subversion/auth/svn.simple/*; do
  1183. echo "[UPC024] WARNING: Cleartext subversion passsword file: $FILE"
  1184. done
  1185. fi
  1186. done
  1187.  
  1188. # Check for private SSH keys in home directories
  1189. section "Checking for Private SSH Keys in home directories"
  1190. for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do
  1191. if [ -d "$HOMEDIR/.ssh" ]; then
  1192. PRIV_KEYS=`grep -l 'BEGIN [RD]SA PRIVATE KEY' $HOMEDIR/.ssh/* 2>/dev/null`
  1193. if [ -n "$PRIV_KEYS" ]; then
  1194. for KEY in $PRIV_KEYS; do
  1195. ENC_KEY=`grep -l 'ENCRYPTED' "$KEY" 2>/dev/null`
  1196. if [ -n "$ENC_KEY" ]; then
  1197. echo "[UPC025] WARNING: Encrypted private SSH key found in $KEY"
  1198. else
  1199. echo "[UPC026] WARNING: Unencrypted private SSH key found in $KEY"
  1200. fi
  1201. done
  1202. fi
  1203. fi
  1204. done
  1205.  
  1206. # Check for public SSH keys in home directories
  1207. section "Checking for Public SSH Keys in home directories"
  1208. for HOMEDIR in `cut -f 6 -d : /etc/passwd`; do
  1209. if [ -r "$HOMEDIR/.ssh/authorized_keys" ]; then
  1210. KEYS=`grep '^ssh-' $HOMEDIR/.ssh/authorized_keys 2>/dev/null`
  1211. if [ -n "$KEYS" ]; then
  1212. echo "[UPC027] WARNING: Public SSH Key Found in $HOMEDIR/.ssh/authorized_keys"
  1213. fi
  1214. fi
  1215. done
  1216.  
  1217. section "Checking classpath permissions for Java processes"
  1218. ps -ef | grep -i '\-classpath' | grep -v grep | while read LINE
  1219. do
  1220. U=`echo $LINE | awk '{print $1}'`
  1221. CLASSPATH=`echo $LINE | sed 's/.*classpath //' | sed 's/ .*//'`
  1222. for P in `echo $CLASSPATH | sed 's/:/ /g'`; do
  1223. check_perms "$P is in the classpath for a java process run by $U." "$P" $U
  1224. done
  1225. done
  1226.  
  1227. # Check for any SSH agents running on the box
  1228. section "Checking for SSH agents"
  1229. AGENTS=`ps -ef | grep ssh-agent | grep -v grep`
  1230. if [ -n "$AGENTS" ]; then
  1231. echo "[UPC028] WARNING: There are SSH agents running on this system:"
  1232. ps -ef | grep ssh-agent | grep -v grep
  1233. # for PID in `ps aux | grep ssh-agent | grep -v grep | awk '{print $2}'`; do
  1234. for SOCK in `ls /tmp/ssh-*/agent.* 2>/dev/null`; do
  1235. SSH_AUTH_SOCK=$SOCK; export SSH_AUTH_SOCK
  1236. AGENT_KEYS=`ssh-add -l | grep -v 'agent has no identities.' 2>/dev/null`
  1237. if [ -n "$AGENT_KEYS" ]; then
  1238. echo "[UPC029] WARNING: SSH Agent has keys loaded [SSH_AUTH_SOCK=$SSH_AUTH_SOCK]"
  1239. ssh-add -l
  1240. fi
  1241. done
  1242. else
  1243. echo "No SSH agents found"
  1244. fi
  1245.  
  1246. # Check for any GPG agents running on the box
  1247. section "Checking for GPG agents"
  1248. AGENTS=`ps -ef | grep gpg-agent | grep -v grep`
  1249. if [ -n "$AGENTS" ]; then
  1250. echo "[UPC030] WARNING: There are GPG agents running on this system:"
  1251. ps aux | grep gpg-agent | grep -v grep
  1252. else
  1253. echo "No GPG agents found"
  1254. fi
  1255.  
  1256. # Check files in /etc/init.d/* can't be modified by non-root users
  1257. section "Checking startup files (init.d / rc.d) aren't writable"
  1258. for DIR in /etc/init.d /etc/rc.d /usr/local/etc/rc.d; do
  1259. if [ -d "$DIR" ]; then
  1260. for FILE in $DIR/*; do
  1261. F=`echo "$FILE" | sed 's/^.*\///'`
  1262. if [ "$F" = "*" ]; then
  1263. echo "No user startup script found in $DIR. Skipping checks."
  1264. continue
  1265. fi
  1266. echo Processing startup script $FILE
  1267. check_called_programs "$FILE is run by root at startup." $FILE root
  1268. done
  1269. fi
  1270. done
  1271.  
  1272. section "Checking if running programs are writable"
  1273. if [ "$OS" = "solaris" ]; then
  1274. # use the output of ps command
  1275. ps -ef -o user,comm | while read LINE
  1276. do
  1277. USER=`echo "$LINE" | awk '{print $1}'`
  1278. PROG=`echo "$LINE" | awk '{print $2}'`
  1279. check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER"
  1280. done
  1281. elif [ "$OS" = "aix" ]; then
  1282. # use the output of ps command
  1283. ps -ef -o user,comm | while read LINE
  1284. do
  1285. USER=`echo "$LINE" | awk '{print $1}'`
  1286. PROG=`echo "$LINE" | awk '{print $2}'`
  1287. check_called_programs "`which $PROG` is currently running as $USER." "`which $PROG`" "$USER"
  1288. done
  1289. elif [ "$OS" = "bsd" ]; then
  1290. # use the output of ps command
  1291. ps aux | while read LINE
  1292. do
  1293. USER=`echo "$LINE" | awk '{print $1}'`
  1294. PROG=`echo "$LINE" | awk '{print $11}'`
  1295. check_called_programs "$PROG is currently running as $USER." "$PROG" "$USER"
  1296. done
  1297. elif [ "$OS" = "hpux" ]; then
  1298. # use the output of ps command
  1299. ps -ef | while read LINE
  1300. do
  1301. USER=`echo "$LINE" | awk '{print $1}'`
  1302. PROG1=`echo "$LINE" | awk '{print $8}'`
  1303. PROG2=`echo "$LINE" | awk '{print $9}'`
  1304. if [ -f "$PROG1" ]; then
  1305. check_called_programs "$PROG is currently running as $USER." "$PROG1" "$USER"
  1306. fi
  1307. if [ -f "$PROG2" ]; then
  1308. check_called_programs "$PROG is currently running as $USER." "$PROG2" "$USER"
  1309. fi
  1310. done
  1311. elif [ "$OS" = "linux" ]; then
  1312. # use the /proc file system
  1313. for PROCDIR in /proc/[0-9]*; do
  1314. unset PROGPATH
  1315. PID=`echo $PROCDIR | cut -f 3 -d /`
  1316. echo ------------------------
  1317. echo "PID: $PID"
  1318. if [ -d "$PROCDIR" ]; then
  1319. if [ -r "$PROCDIR/exe" ]; then
  1320. PROGPATH=`ls -l "$PROCDIR/exe" 2>&1 | sed 's/ (deleted)//' | awk '{print $NF}'`
  1321. else
  1322. if [ -r "$PROCDIR/cmdline" ]; then
  1323. P=`cat $PROCDIR/cmdline | tr "\0" = | cut -f 1 -d = | grep '^/'`
  1324. if [ -z "$P" ]; then
  1325. echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
  1326. else
  1327. PROGPATH=$P
  1328. fi
  1329. else
  1330. echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
  1331. continue
  1332. fi
  1333. fi
  1334. get_owner $PROCDIR; OWNER=$GET_OWNER_RETURN
  1335. echo "Owner: $OWNER"
  1336. else
  1337. echo "ERROR: Can't find OWNER. Process has gone."
  1338. continue
  1339. fi
  1340.  
  1341. if [ -n "$PROGPATH" ]; then
  1342. get_owner $PROGPATH; PROGOWNER=$GET_OWNER_RETURN
  1343. echo "Program path: $PROGPATH"
  1344. check_called_programs "$PROGPATH is currently running as $OWNER." $PROGPATH $OWNER
  1345. fi
  1346.  
  1347. if [ "$MODE" = "detailed" ]; then
  1348. for FILE in $PROCDIR/fd/*; do
  1349. F=`echo "$FILE" | sed 's/^.*\///'`
  1350. if [ "$F" = "*" ]; then
  1351. continue
  1352. fi
  1353. check_perms "$FILE is an open file descriptor for process $PID running as $OWNER." $FILE $OWNER
  1354. done
  1355. fi
  1356. done
  1357. fi
  1358.  
  1359. section "Checking exploit mitigation"
  1360. if [ "$MODE" = "detailed" ]; then
  1361. if [ "$OS" = "solaris" ]; then
  1362. NX=`grep noexec_user_stack /etc/system | grep -v _log | grep 1`
  1363. if [ -z "$NX" ]; then
  1364. echo "[UPC031] WARNING: No NX"
  1365. fi
  1366.  
  1367. NXLOG=`grep noexec_user_stack_log /etc/system | grep 1`
  1368. if [ -z "$NXLOG" ]; then
  1369. echo "[UPC032] WARNING: No NX logging"
  1370. fi
  1371.  
  1372. AUDIT=`grep c2audit:audit_load /etc/system | grep 1`
  1373. if [ -z "$AUDIT" ]; then
  1374. echo "[UPC033] WARNING: Auditing not enabled"
  1375. fi
  1376. fi
  1377. if [ "$OS" = "aix" ]; then
  1378. false
  1379. fi
  1380. if [ "$OS" = "hpux" ]; then
  1381. NX=`kmtune -q executable_stack | grep executable_stack | awk '{print $2}'`
  1382. if [ "$NX" -eq 1 ]; then
  1383. echo "[UPC034] WARNING: No NX"
  1384. elif [ "$NX" -eq 2 ]; then
  1385. echo "[UPC035] WARNING: NX set to logging only"
  1386. fi
  1387. fi
  1388. if [ "$OS" = "linux" ]; then
  1389. ASLR=`sysctl kernel.randomize_va_space | awk '{print $3}'`
  1390. if [ "$ASLR" -eq 0 ]; then
  1391. echo "[UPC036] WARNING: No ASLR"
  1392. elif [ "$ASLR" -eq 1 ]; then
  1393. echo "[UPC037] WARNING: Conservative ASLR"
  1394. fi
  1395.  
  1396. MMAP=`cat /proc/sys/vm/mmap_min_addr`
  1397. if [ "$MMAP" -eq 0 -o "$MMAP" = "" ]; then
  1398. echo "[UPC038] WARNING: mmap allows map to 0"
  1399. fi
  1400.  
  1401. if [ ! -f /selinux/enforce ]; then
  1402. echo "[UPC039] WARNING: SELinux does not enforce"
  1403. fi
  1404.  
  1405. for PROCDIR in /proc/[0-9]*; do
  1406. unset PROGPATH
  1407. PID=`echo $PROCDIR | cut -f 3 -d /`
  1408. echo ------------------------
  1409. echo "PID: $PID"
  1410. if [ -d "$PROCDIR" ]; then
  1411. if [ -r "$PROCDIR/exe" ]; then
  1412. PROGPATH=`ls -l "$PROCDIR/exe" 2>&1 | sed 's/ (deleted)//' | awk '{print $NF}'`
  1413. else
  1414. if [ -r "$PROCDIR/cmdline" ]; then
  1415. P=`cat $PROCDIR/cmdline | tr "\0" = | cut -f 1 -d = | grep '^/'`
  1416. if [ -z "$P" ]; then
  1417. echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
  1418. else
  1419. PROGPATH=$P
  1420. fi
  1421. else
  1422. echo "ERROR: Can't find full path of running program: "`cat $PROCDIR/cmdline`
  1423. continue
  1424. fi
  1425. fi
  1426. else
  1427. echo "ERROR: Can't find full path of running process. Process has gone."
  1428. continue
  1429. fi
  1430. if [ -n "$PROGPATH" ]; then
  1431. echo "Program path: $PROGPATH"
  1432. NX=`grep stack $PROCDIR/maps | grep -v "rw-"`
  1433. if [ -n "$NX" ]; then
  1434. echo "[UPC040] WARNING: NX not enabled"
  1435. fi
  1436.  
  1437. SSP=`objdump -D $PROCDIR/exe | grep stack_chk`
  1438. if [ -z "$SSP" ]; then
  1439. echo "[UPC041] WARNING: SSP not enabled"
  1440. fi
  1441. fi
  1442. done
  1443. find / \( -perm -u+s -o -perm -g+s \) -type f | while read PROGPATH; do
  1444. echo "Program path: $PROGPATH"
  1445. ls -la $PROGPATH
  1446.  
  1447. SSP=`objdump -D $PROGPATH | grep stack_chk`
  1448. if [ -z "$SSP" ]; then
  1449. echo "[UPC042] WARNING: SSP not enabled"
  1450. fi
  1451. done
  1452. find / -type f -exec /sbin/getcap {} \; 2>/dev/null | grep "=" | awk '{print $1}' | while read PROGPATH; do
  1453. echo "Program path: $PROGPATH"
  1454. /sbin/getcap $PROGPATH
  1455. SSP=`objdump -D $PROGPATH | grep stack_chk`
  1456. if [ -z "$SSP" ]; then
  1457. echo "[UPC042] WARNING: SSP not enabled"
  1458. fi
  1459. done
  1460. fi
  1461. fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement