編寫 pam_python 模組:“KeyError: getspnam(): name not found”
我正在使用一個
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'
完全相同的錯誤。
因此,由此我可以假設當通過 pam
spwd.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 的答案格式。