ProbeCheck

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:

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
Neddy, Henry, and Minnie appear courtesy of the The Goon Show, a BBC radio program starting Peter Sellers, Harry Secombe, and (especially) Spike Milligan. :-)

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.


http://Yost.com/computers/probecheck/ - this page
2005-03-25 Created
2005-03-26 Modified extensively
2005-03-29 Modified
2005-07-11 Modified to add License