编写 pam_python 模块:“KeyError:getspnam():未找到名称”

编写 pam_python 模块:“KeyError:getspnam():未找到名称”

我正在使用一个pam_python模块来记录 SSH 尝试中使用的用户名和密码。

/etc/pam.d/sshd添加了这一行:

auth       requisite    pam_python.so /lib64/security/pwreveal.py

这是/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

/var/log/messages这在一定程度上是有效的,在SSH 尝试失败后我看到以下输出(在本例中,我来自另一个本地开发服务器):

Mar  3 14:35:59 localhost sshd: SSH Attack Logged: Remote Host: 192.168.1.7 (root:root123)

我的问题是,无论用户名/密码组合是否正确,脚本总是在 /var/log/secure 中输出相同的错误并无法验证(因此当我使用这个 python 脚本时,SSH 实际上已经损坏):

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

我知道“spwd”是影子密码数据库,我在网上找到了一些信息,表明在这种情况下,“未找到名称”更准确地描述为“权限被拒绝”。因此,作为测试,我确保 sshd 用户具有对 /etc/shadow 的读取权限 - 但这没有帮助。

我不确定我搜索的思路是否正确。有什么帮助吗?

注意:我意识到在服务器上运行 SSH 密码记录并不是一件好事。我正在一个只有我才能访问的个人开发箱上执行此操作。这是一个“只是为了好玩”的项目。

编辑- 作为测试,我创建了一个独立的 python 脚本,它简单地执行以下操作:

import spwd

test = spwd.getspnam("myusername")[1]

print test

以 root 身份运行此脚本会提取“myusername”密码的哈希密码。如果我故意拼错该用户名,那么我实际上是在尝试查找影子文件中不存在的用户名,我会收到此错误:

KeyError: 'getspnam(): name not found'

完全相同的错误。

因此,我可以假设,当通过 pamspwd.getspnam()从内部运行时pwreveal.py,它无法找到用户。尽管当它在单独的脚本中独立运行时,它可以找到。

为什么会这样?

答案1

我不确定我是否正确理解了您的问题,但您试图说您的脚本在从 PAM 脚本调用时始终会回溯。当您写入无效用户(不存在用户)时,您可以模拟相同的行为。

那么让我们开始长话短说吧。KeyError异常告诉您由于某种原因未在数据库中找到该用户。在您的第二个示例中,这显然是因为用户实际上不存在,并且这是预期的行为——这就是 Python 中异常的工作方式,不是吗?

您最初的问题很可能是由 CentOS 中的 SELinux 策略引起的。正常进程无法读取/etc/shadow。当您从 pam 堆栈下启动 python 脚本时,暂停它并查看进程上下文(使用ps auxfZ),您将看到脚本正在使用的实际上下文。您还很可能会在/var/log/audit/audit.log(或ausearch -m AVC)中看到一些 AVC 消息,说明哪个进程被禁止访问该shadow文件。

那么如何解决呢?第一种可能性是暂时将 SELinux 切换到以permissive确保它是原因(setenfoce 0)。然后,它应该开始工作。但你不应该满足于此,如果你想正确地做到这一点,你应该尝试调整/编写脚本的策略,但这不符合 Serverfault 上答案的格式。

相关内容