You are not logged in.

#1 2020-12-08 14:38:53

TheCoon
Member
Registered: 2016-05-10
Posts: 42

Perform action based on number of failed login/authentication attempts

I'd like to perform certain actions or run a script when a set number of failed user login attempts are recorded. I'd also like to make use of the actual number (count) of failed login attempts if possible.

I used to achieve this using pam_tally2, but as I discovered from this thread, pam_tally/pam_tally2 are obsolete.

How can this be achieved today? I know that the file /var/run/faillock/$USER contains some logging of failed attempts, but its format is unclear.

Thanks for any info.

Offline

#2 2020-12-08 15:21:32

V1del
Forum Moderator
Registered: 2012-10-16
Posts: 25,312

Re: Perform action based on number of failed login/authentication attempts

Mod note: Moving to NC

Online

#3 2020-12-08 16:04:16

seth
Member
From: Won't reply 2 private help req
Registered: 2012-09-03
Posts: 77,387

Re: Perform action based on number of failed login/authentication attempts

There's a "faillock" binary to inspect the log.

Offline

#4 2020-12-08 17:22:05

TheCoon
Member
Registered: 2016-05-10
Posts: 42

Re: Perform action based on number of failed login/authentication attempts

V1del thanks for moving the thread.

Thank you for pointing out the faillock binary, seth.

faillock outputs the following:

faillock --user myuser
myuser:
When                Type  Source                                           Valid
2020-12-08 15:01:16 TTY   /dev/pts/12                                          V
2020-12-08 15:01:19 TTY   /dev/pts/12                                          V
2020-12-08 15:01:21 TTY   /dev/pts/12                                          V
2020-12-08 15:01:46 TTY   tty2                                                 V

Where the "V" under the "Valid" column actually signifies a failed login (not very intuitive).
So if I were to count the V's I could get the current number of failed logins.

What would be the most efficient way to know exactly when these failures occur? In other words, what would trigger my custom action/script upon login failure?

Here is a similar question and a hacky solution which points out faillock's shortcomings when compared to pam_tally2: https://unix.stackexchange.com/question … -get-count

Last edited by TheCoon (2020-12-08 17:24:06)

Offline

#5 2020-12-08 18:02:47

loqs
Member
Registered: 2014-03-06
Posts: 19,008

Re: Perform action based on number of failed login/authentication attempts

Monitor the directory /run/faillock or in /etc/pam.d/system-auth change

auth       [default=die]               pam_faillock.so      authfail

to something such as

auth       [default=fail]               pam_faillock.so      authfail
auth       [default=die]                pam_exec.so /path/to/binary options

Edit:
The pam based approach will not be triggered by logins rejected by

auth       required                    pam_faillock.so      preauth

only the failed attempts leading up to faillock being activated.

Last edited by loqs (2020-12-08 18:24:41)

Offline

#6 2020-12-09 11:57:17

TheCoon
Member
Registered: 2016-05-10
Posts: 42

Re: Perform action based on number of failed login/authentication attempts

Thanks for the suggestion, loqs.

I am currently working on a custom solution which makes use of inotifywait for monitoring changes to the log file, which in turn checks the log using faillock in order to get the number of failed attempts.

https://gist.github.com/nyancow/410e1de … 7a163a8f18

#!/usr/bin/env bash

# https://gist.github.com/nyancow/410e1dedc00d7d7dd237137a163a8f18

SCRIPTNAME=`basename "$0"`

REQS=(faillock inotifywait)
for REQ in "${REQS[@]}"
do
	if ! command -v ${REQ} &> /dev/null
    then
        printf "${REQ} binary could not be found, exiting. \n"
        exit 1
    fi
done

if [ $# -eq 0 ]
then
    printf "No arguments supplied. \n"
    printf "Specify the username to watch and the maximum number \n"
    printf "of failed attempts before triggering an action.\n\n"
    printf "\t${SCRIPTNAME} <username> <limit> \n\n"
    exit 0
fi

# User to watch
WATCHUSER="${1}"
# Fail limit
FAILLIMIT="${2}"

if [ -n "$FAILLIMIT" ] && [ "$FAILLIMIT" -eq "$FAILLIMIT" ] 2>/dev/null; then
    printf "Fail limit set to ${FAILLIMIT} \n"
else
    printf "Specified limit is not a number \n"
    exit 0
fi

# Runs when the faillock file is modified
triggered() {
    # Get faillock binary output
    LOGOUTPUT=$(/usr/bin/faillock --user ${WATCHUSER})
    # Count the number of "V" occurrences
    FAILCOUNT=$(echo ${LOGOUTPUT} | grep -Eo "\bV\b" | wc -l)
    # Check if fail limit reached
    if [ "$FAILCOUNT" -gt "$FAILLIMIT" ]; then
        MSG="Failed login for ${WATCHUSER} more than ${FAILLIMIT} times"
        # /usr/bin/tgalert "${MSG}"
        logger "${MSG}"
    fi
}

# https://superuser.com/a/181543
# Monitor the faillock log file for the specified user
# Call triggered() when the file is modified
/usr/bin/inotifywait --quiet --monitor --event modify /var/run/faillock/${WATCHUSER} |
while read -r filename event; do
    triggered
done

I will probably run this script using a systemd service on boot.
If anyone has thoughts or suggestions for improving this approach, I'd love to hear them.

EDIT:

Here's the systemd service file I'm using:

[Unit]
Description=Monitor faillock entries

[Service]
Type=simple
ExecStart=/usr/bin/failmon myuser 2
PIDFile=/run/failmon.pid

[Install]
WantedBy=multi-user.target

Last edited by TheCoon (2020-12-09 13:34:27)

Offline

Board footer

Powered by FluxBB