I'm using a pam_python
module to log usernames and passwords used in SSH attempts.
in /etc/pam.d/sshd
I added this line:
auth requisite pam_python.so /lib64/security/pwreveal.py
This is /lib64/security/pwreveal.py
:
import crypt, spwd, syslog
def auth_log(msg):
"""Send errors to default auth log"""
syslog.openlog(facility=syslog.LOG_AUTH)
syslog.syslog("SSH Attack Logged: " + msg)
syslog.closelog()
def check_pw(user, password):
auth_log("User: " + user + " Password: " + password)
"""Check the password matches local unix password on file"""
# try:
hashed_pw = spwd.getspnam(user)[1]
# except KeyError,e:
# return False
return crypt.crypt(password, hashed_pw) == hashed_pw
def pam_sm_authenticate(pamh, flags, argv):
try:
user = pamh.get_user()
except pamh.exception, e:
return e.pam_result
if not user:
return pamh.PAM_USER_UNKNOWN
try:
resp = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, 'Password:'))
except pamh.exception, e:
return e.pam_result
if not check_pw(user, resp.resp):
auth_log("Remote Host: %s (%s:%s)" % (pamh.rhost, user, resp.resp))
return pamh.PAM_AUTH_ERR
return pamh.PAM_SUCCESS
def pam_sm_setcred(pamh, flags, argv):
return pamh.PAM_SUCCESS
def pam_sm_acct_mgmt(pamh, flags, argv):
return pamh.PAM_SUCCESS
def pam_sm_open_session(pamh, flags, argv):
return pamh.PAM_SUCCESS
def pam_sm_close_session(pamh, flags, argv):
return pamh.PAM_SUCCESS
def pam_sm_chauthtok(pamh, flags, argv):
return pamh.PAM_SUCCESS
This works to an extent, I see the following output in /var/log/messages
after a failed SSH attempt (in this case, me from another local dev server):
Mar 3 14:35:59 localhost sshd: SSH Attack Logged: Remote Host: 192.168.1.7 (root:root123)
My problem is that regardless of whether the username/password combination is correct, the script always outputs the same error in /var/log/secure and fails to authenticate (so SSH is effectively broken while I'm using this python script):
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: Traceback (most recent call last):
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: File "/lib64/security/pwreveal.py", line 32, in pam_sm_authenticate
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: if not check_pw(user, resp.resp):
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: File "/lib64/security/pwreveal.py", line 13, in check_pw
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: hashed_pw = spwd.getspnam(user)[1]
Mar 3 14:50:41 localhost /lib64/security/pwreveal.py[13328]: KeyError: getspnam(): name not found
I know that 'spwd' is the shadow password database and I found some information online that suggested that in this case "name not found" was more accurately described as 'permission denied'. So as a test I made sure that the sshd user had read access to /etc/shadow - but this didn't help.
I'm not sure if I'm searching along the right lines or not. Any help?
Note: I realise that SSH password logging is not a desirable thing to have running on a server. I am doing this on a personal development box that only I have access to. This is a 'just for fun' project.
Edit - as a test I created a standalone python script that simply does this:
import spwd
test = spwd.getspnam("myusername")[1]
print test
Running this script as root pulled out the hashed password for the 'myusername' password. If I intentionally misspell that username so I am effectively trying to look for a username that doesn't exist in the shadow file, I get this error:
KeyError: 'getspnam(): name not found'
The exact same error.
So from this I can assume that when spwd.getspnam()
is run from within pwreveal.py
via pam, it is unable to find the user. Although when it is run independently in a separate script, it can.
Why would this be?