The gatekeeper pattern adds a post-authentication challenge to SSH sessions using ForceCommand. The concept was inspired by a scene in a movie where a system required answering riddles before granting access.
WARNING: This is a not a real security mechanism and shouldn't be treated as such. It is purely useful as a gag or potentially as something fun to throw into a CTF.
First we need to make a script to handle the additional authentication. Please note that the following script is just an example. Most of the security is in place but you will want to implement your own logic for the questions and answers. I highly recommend using logic that changes periodically but can be deduced remotely by the client.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
#!/bin/sh
# gatekeeper.sh - Post-login access question script
# In the event that a user tries to get crafty and Ctrl-C out of the script
# we'll just kill the connection
trap jail INT
jail() {
kill -9 $PPID
exit 0
}
# Once a user logs in, check to see if they just wanted a shell.
# SSH_ORIGINAL_COMMAND will be null (-z) if they did
if [ -z "$SSH_ORIGINAL_COMMAND" ]; then
# The answer the user needs to know, a function or call to another script
# could be used to generate this answer based on any number of resources
# available to the system. This could include querying an internal web
# script to get a daily password user's of a site have access to (and
# perhaps are supposed to be checking)
local CORRECT_ANSWER="muffins"
# Message displayed to the user before being prompted, I'm going to assume
# the user knows the question in this case what's the admin's favorite
# breakfast
echo -n "Gatekeeper token authentication required: "
# Get the user's answer. If the answer is correct execute the command.
# If the answer is wrong, log the attempt and kill the connection.
while read -s inputline; do
RESPONSE="$inputline"
echo
if [ $CORRECT_ANSWER = "${RESPONSE}" ]; then
echo "Gatekeeper authentication accepted."
$SHELL -l
exit 0
else
logger "Gatekeeper: $USER login failed from $SSH_CLIENT"
kill -9 $PPID
exit 0
fi
done
fi
# This command will bypass the gatekeeper script if the user tries to rsync as
# this script will break rsync. It creates a fresh shell just for good measure.
#if [ `echo $SSH_ORIGINAL_COMMAND | awk '{print $1}'` = rsync ]; then
# $SHELL -c "$SSH_ORIGINAL_COMMAND"
# exit 0
#fi
# If a user tried to execute something other than an 'approved' command just
# kill the session. This will prevent SCP and SFTP unless they are configured
# to bypass the script.
kill -9 $PPID
exit 0
|
Put this script in /etc/ssh/gatekeeper.sh and change its permissions to 755 with the owner being root. To make the SSH server pass off control to the Gatekeeper script once its done authenticating a user, use the ForceCommand directive in the SSHd config file (/etc/ssh/sshd_config). Add the following line to the end of the config and restart the SSH daemon.
ForceCommand /etc/ssh/gatekeeper.sh
Assuming everything went according to plan, when you SSH into the remote server once you are done authenticating it will ask for the token. Putting in 'muffins' should get you to your shell, while anything else will kill the connection.