Linux

編寫 pam_python 模組:“KeyError: getspnam(): name not found”

  • March 5, 2017

我正在使用一個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

這在一定程度上有效,我在 SSH 嘗試失敗後看到以下輸出/var/log/messages(在這種情況下,我來自另一個本地開發伺服器):

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,它無法找到使用者。雖然當它在單獨的腳本中獨立執行時,它可以。

為什麼會這樣?

我不確定我的問題是否正確,但您想說的是,當從 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 的答案格式。

引用自:https://serverfault.com/questions/836128