A shell script to report failed and successful authentication attempts
Download the ProbeCheck application here. This double-clickable application is a simple RealBasic application wrapper for the probecheck
shell script described below. I make no warranties, and I offer no free support! Many thanks to Kem Tekinay of MacTechnologies Consulting for the wrapper.
For more information see the MacInTouch report on Access Monitoring and SSH.
Here’s what the output from probecheck looks like:
Neddy, Henry, and Minnie appear courtesy of the The Goon Show, a BBC radio program starting Peter Sellers, Harry Secombe, and (especially) Spike Milligan. :-)
Probes since start of log file, Dec 21 16:52:46: 37 appserver 50 cyrus 39 daemon 37 eppc 1 min 39 neddy 1 neddy uid 502 41 lp 36 mailman 50 mysql 52 nobody 37 postfix 36 qtss 680 root 38 smmsp 37 sshd 35 unknown 51 www 62 henry 5 henry uid 502 These probed accounts are nonexistent: min These probed accounts cannot be guessed: appserver cyrus daemon eppc lp mailman mysql nobody postfix qtss root smmsp sshd unknown www These probed accounts are open to password guessing: neddy henry minnie Successful authentications since start of log file, Dec 21 16:52:46: 316 neddy 7 henry 2 minnie
The best way to stop all this probing is to disable Remote Login in the Sharing panel of System Preferences. The next best way is to get ssh
to listen on a nonstandard port. Apple should make this easy to do, but currently it is quite complicated, and I won’t go into it here. (Please don’t email me to ask me.)
Below is the shell script. If you copy and paste it into TextEdit, be sure to select
Format > Make Plain Text
#!/bin/zsh # probecheck # Run this to see failed authentication attempts, # for example failed attempts to login via ssh. # Commented out the check for no-password accounts because the # code itself causes the logging of an authorization failure. # Is there a better way to do that? # Copyright 2005 Dave Yost <Dave@Yost.com> # All rights reserved. # This version is # probecheck 1.0 2005-03-29 # which at time of this publication can be found at: # http://Yost.com/computers/probecheck # Redistribution and use in the form of source code or derivative data built # from the source code, with or without modification, are permitted provided # that the following conditions are met: # 1. THE USER AGREES THAT THERE IS NO WARRANTY. # 2. If and only if appropriate, the above phrase "This version is" must be # followed by the phrase "a modified form of" or "extracted from" or "extracted # and modified from". # 3. Redistributions of source code must retain this notice intact. # 4. Redistributions in the form of derivative data built from the source # code must reproduce this notice intact in the documentation and/or other # materials provided with the distribution. # 5. Neither the name of Dave Yost nor the names of its contributors may be # used to endorse or promote products derived from this software without # specific prior written permission. # 6. If redistributed as part of a commercial product, written permission, # posted on the Dave Yost's web site is required. # This notice comprises all text from "Copyright" above through the end of # this sentence. if [[ $(whoami) = root ]] ; then echo "You can't run probecheck as root." exit 2 fi logfile=/var/log/secure.log if [[ ! -e $logfile ]] ; then echo "Nothing is logged; The log file doesn't exit." exit elif [[ ! -s $logfile ]] ; then echo "Nothing is logged; The log file is empty." exit fi # This proram can report only activity from the start date of the log file. startDate=$(sudo awk 'NR == 1 { print $1, $2, $3 }' $logfile) # Extract lines from the log file. # The first word is the account probed. # Additional words identify the type of probe, if other than a login attempt. # Typical example is # root uid 502 # which means that the account whose ID is 502 tried to authenticate as root. trimmedProbes=$( sudo grep "failed to auth" $logfile \ | sed "s/^.*com.apple.SecurityServer: \(.*\) failed to authenticate[ as]*user \([^ ]*\).*$/\2 \1/" \ | sed 's/ authinternal//') if [[ -z $trimmedProbes ]] ; then echo No probes logged since start of log file, ${startDate}. exit fi # Output a summary of how many of each kind of probe for each account. echo Probes since start of log file, $startDate: echo "$( echo $trimmedProbes \ | sort \ | uniq -c \ | sort +1 )" # Get just the account names probedAccounts=($( echo $trimmedProbes \ | awk '{ print $1 }' \ | sort -u )) # Find out all the accounts on the system accounts=($(nicl . -list /users | awk '{ print $2 }' | sort)) otherAccounts=() #accountsWideOpen=() accountsUnguessable=() accountsGuessable=() for x in ${accounts[@]} do # if (su $x < /dev/null 2> /dev/null) ; then # accountsWideOpen+=$x # else otherAccounts+=$x # fi done for x in ${otherAccounts[@]} do passwd=$(nicl . -read /users/$x passwd | awk '{ print $2 }' ) if [[ "$passwd" = '*' ]] ; then accountsUnguessable+=$x else accountsGuessable+=$x fi done #probesWideOpen=() probesUnguessable=() probesGuessable=() probesNonexistent=() for x in ${probedAccounts[@]} do # if [[ ${${accountsWideOpen[(r)$x]}:+true} = true ]] ; then # probesWideOpen+=$x # elif if [[ ${${accountsGuessable[(r)$x]}:+true} = true ]] ; then probesGuessable+=$x elif [[ ${${accountsUnguessable[(r)$x]}:+true} = true ]] ; then probesUnguessable+=$x else probesNonexistent+=$x fi done printArrayIndented() { for xind do echo " "$xind done } # Report if any probed accounts are nonexistent. if [[ -z "$probesNonexistent" ]] ; then echo No probed accounts are nonexistent. else echo These probed accounts are nonexistent: printArrayIndented $probesNonexistent[@] fi # Report if any probed accounts are unguessable. if [[ -z "$probesUnguessable" ]] ; then echo No probed accounts are unguessable. else echo These probed accounts cannot be guessed: printArrayIndented $probesUnguessable[@] fi # Report if any probed accounts are vulnerable to password guessing. if [[ -z "$probesGuessable" ]] ; then echo No probed accounts are guessable. else echo These probed accounts are open to password guessing: printArrayIndented $probesGuessable[@] fi # Report information about accounts that have no password. #if [[ -z "$accountsWideOpen" ]] ; then # echo There are no accounts with unset passwords. Good. #else # echo VERY BAD - These accounts have unset passwords: # printArrayIndented $accountsWideOpen[@] # if [[ -z "$probesWideOpen" ]] ; then # echo No accounts with unset passwords were unsuccessfully probed. # else # echo "These probed accounts have no passwords (and it's a miracle the probe failed):" # printArrayIndented $probesWideOpen[@] # echo Be sure to look for these accounts in the list below of successful authentications. # fi #fi # Report successful authentications trimmedAuthentications=$( sudo grep "authenticated" $logfile \ | sed "s/^.*com.apple.SecurityServer: \(.*\) authenticated[ as]*user \([^ ]*\).*$/\2 \1/" \ | sed 's/ authinternal//') if [[ -z $trimmedAuthentications ]] ; then echo No accounts have been authenticated since start of log file, ${startDate}. else # Output a summary of how many of each kind of authentication for each account. echo Successful authentications since start of log file, $startDate: echo "$( echo $trimmedAuthentications \ | sort \ | uniq -c \ | sort +1 )" fi
The report could be more meaningful if each log entry would give the origin of the authentication attempt: localhost, same subnet, or somewhere else.