開發與維運

SSH登錄提示Permission Denied的排查

背景

用戶反饋使用密碼無法正常登錄,提示“Permission Denied”,需要重置密碼後才能正常,而相同的密碼在一個月前能正常登錄,一共有兩臺實例有這樣的現象。

分析

一般來說,類似問題可以從幾個方面來考慮可能性:

  • SSH server配置問題
  • 服務器密碼被改動過或者密碼相關配置文件被改動過
  • 通過遠程或者VNC的方式鍵入密碼傳遞到系統內時候發生了變動
  • 記錯密碼

以上幾點我們一一進行排查,由於要保留現場,無法重置密碼後再登錄查看,我們可以通過將系統盤快照做成雲盤來繞過登錄的環節,從而進入系統。
掛載快照盤,我們通過chroot進入系統,要定位是否密碼有改動或者配置文件有變動,我們首先通過stat查看/etc/ssh/目錄下各文件,從mtime/ctime時間戳來看,最近的改動在一年多前,說明sshd如果是讀取的正常路徑配置文件,那麼用戶名和密碼以及sshd相關配置都沒有被改動過。

111.png

單方面看MAC時間可能說服力不夠,我們通過查看配置文件和對比測試進一步說明sshd正常工作且服務器端沒有改動:

  1. 實際查看/etc/ssh/sshd_conf配置文件,發現是保持的默認配置,沒有異常改動。
  2. 有快照的前提下,嘗試修改密碼/重置密碼,之後再登錄發現可以正常登錄。

以上排查驗證了服務器端沒有改動且sshd工作正常,為了驗證是否輸入密碼到sshd讀取過程是否存在異常,我們掛載快照盤並chroot進入系統,通過strace來跟蹤sshd進程以及其fork出的進程,之後通過ssh自己系統來規避網絡上的影響。我們可以看到輸入的密碼在被讀取時候並沒有發生改變。也能從strace輸出中瞭解到去讀取的配置文件是正常路徑的配置文件。說明輸入的密碼在驗證之前也沒有被修改過。
基於以上信息,我們基本可以肯定是用戶密碼記錄存在問題。但用戶也表示從數據庫讀取的,期間沒動過數據庫,應該不會出現問題,那麼為了更進一步說服用戶,我們可以考慮實際驗證一下用一樣的辦法加密密碼明文後獲取的信息是否和/etc/shadow裡記錄的一致。
我們知道密碼加密後的口令存儲在/etc/shadow文件裡,那麼我們來看一下/etc/shadow文件裡的口令存儲形式,以CentOS 7.2為例:

root:$6$KqCVFlfd$vAARGaFcI5mNWGoOSJeE87ZrI5anStEWZYRz6EkrvXRSuD7X1teJwrWvC2a3YQRSeKuDaqmuN5ScinV/fvOyy0:17497:0:99999:7:::

這裡引用wiki的註解:

User login name
salt and hashed password OR a status exception value e.g.:
"$id$salt$hashed", the printable form of a password hash as produced by crypt (C), where "$id" is the algorithm used. (On GNU/Linux, "$1$" stands for MD5, "$2a$" is Blowfish, "$2y$" is Blowfish (correct handling of 8-bit chars), "$5$" is SHA-256 and "$6$" is SHA-512, other Unix may have different values, like NetBSD. Key stretching is used to increase password cracking difficulty, using by default 1000 rounds of modified MD5, 64 rounds of Blowfish, 5000 rounds of SHA-256 or SHA-512. The number of rounds may be varied for Blowfish, or for SHA-256 and SHA-512 by using e.g. "$6$rounds=50000$".
Empty string – No password, the account has no password (reported by passwd on Solaris with "NP").
"!" – the account is password locked, user will be unable to log in via password authentication but other methods (e.g. ssh key) may be still allowed.
"LK" or "*" – the account is locked, user will be unable to log in via password authentication but other methods (e.g. ssh key) may be still allowed.
"!!" – the password has never been set (RedHat)
Days since epoch of last password change
Days until change allowed
Days before change required
Days warning for expiration
Days before account inactive
Days since epoch when account expires

這裡我們主要需要關注的部分是$id$salt$hashed,其中$id是加密算法,$salt是混入加密算法的鹽,$hashed是經過加密算法hash對應密碼和鹽的結果。

ID | Method
───────────────────────────
1 | MD5
2a | Blowfish (not in mainline glibc; added in some Linux distributions)
5 | SHA-256 (since glibc 2.7)
6 | SHA-512 (since glibc 2.7)

這種場景加密過程就是將密碼通過加密算法計算得到一個hash串,從hash串是無法反推出密碼的。而加入鹽的目的是增強加密複雜性,規避一些強行破解的辦法。
具體加密算法介紹可以參考:https://en.wikipedia.org/wiki/SHA-2

在實際設置密碼過程中,salt是隨機生成的,shadow文件記錄加密算法、salt以及加密後hash串,而當有用戶登錄時候,會將輸入的密碼與shadow文件中salt基於加密算法重新計算一次然後跟hash串比對,如果相同,則說明密碼正確。
我們有了算法和salt後,那麼就可以實際驗證用戶提供的密碼加密後的hash串是否跟shadow文件中對應用戶的hash串相符。

RHEL 6 and newer - python
• Execute the following one-liner:
$ python -c 'import crypt,getpass; print crypt.crypt(getpass.getpass())'
Password:
$6$Q3dbIWgPMCVBpRZK$QSw1cG41FImM0E8B.Hpx1G8eZGqHALzGg75LLAt.MkFZtVma3MHRGBpFSrXEEdVHwySr8B0JfXAgLHgmpSViI0
In short, the above will prompt for input and then interface with python's implementation of the standard crypt() function, generating a shadow-compatible hash by choosing a random salt and the strongest hash method available (SHA-512)
• For documentation, do as the following demonstrates
$ python
Python 2.6.6 (r266:84292, May 1 2012, 13:52:17)
[GCC 4.4.6 20110731 (Red Hat 4.4.6-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import crypt
help(crypt)
RHEL 5 and newer - perl
• Execute the following one-liner:
$ perl -le 'print "Password:"; stty -echo; chomp($passphrase=); stty echo; @chars = ("a".."z", "A".."Z", 0..9, ".", "/"); $salt .= $chars[rand @chars] for 1..16; print crypt($passphrase, "$6$$salt");'
Password:
$6$RDGTu1VHQPH2NLpw$no4LMowmxaJogzYoIUdsfi7pfTz2EtzN//oRmEe12AEWc2h6NPoQwrWA4KYe4W0OSAUaBLOG8K59kzENV2bvY0
• Notes on the above perl code:
○ This code was tested by the author on RHEL 5 - RHEL 7; however, it is offered without any guarantees or warranty (to use it, ensure the quotation marks and backslashes are kept intact)
○ This code generates a SHA512-hashed password string; to use SHA256 instead, change the maroon-colored $6 to a $5

*以上為RedHat給出的模擬方式

為了讓數據更有說服力,我們先要驗證加密辦法是對的,通過類似方法加密的信息能正確跟shadow文件裡存儲的信息對的上。

222.png

驗證符合後,我們進一步驗證用戶提供的密碼信息。發現從用戶提供的密碼來正向獲取hash串後跟shadow裡root的不匹配,由此進一步說明了是用戶提供的密碼存在問題。

`# cat /mnt/etc/shadow
root:$6$D9.mVsWm$W9XlxzRHWU6B6KFNaPZQPCkXF0GrL.Cq.zzx2H24qaDC4bphDFZqZtD5G.t1Rz1cegl2tyQAdx9W6iBoJTANc.:17013:0:99999:7:::`

`# python -c 'import crypt; printcrypt.crypt("Spidermanwsx123","$6$D9.mVsWm")'
$6$D9.mVsWm$Y8rVe1915SlIkdwOloHhFedpW2MZ7xYOYHy69jXOoZqyodDm5WJOBP4P/EeLP1BjJlibHwovaHqawTWD05c6o1`

Leave a Reply

Your email address will not be published. Required fields are marked *