一,用戶密碼存放在哪裏?
說到這個問題,絕大部分的同學肯定都知道/etc/passwd這個文件,不錯,這個文件裏存儲的就是用戶名,密碼等信息。
每一行都是一個account,每一行有7個信息,分別用 : 隔開,從左往右依次是:用戶名:加密用戶密碼:用戶id:組id:註釋:工作目錄:shell目錄,這些信息被放在一個叫struct passwd的結構體中統一管理,struct passwd結構體包含以下信息:
struct passwd {
char *pw_name; /*用戶名*/
char *pw_passwd; /*加密用戶密碼*/
int pw_uid; /*用戶id*/
int pw_gid; /*組id*/
char *pw_gecos; /*註釋*/
char *pw_dir; /*用戶主目錄*/
char *pw_shell; /*shell目錄*/
};
但是通過查看/etc/passwd文件內容,發現加密密碼一項都用了字符'x'表示。我們理解中的加密密碼應該是一串看不出任何邏輯的字符纔對,怎麼會是一個‘x’呢?
二,/etc/shadow文件
上面一個內容中最後提出了一個疑惑,'x'的來由。這就是一個簡單的歷史遺留問題,早期的posix版本中'x'這個位置確實存放的是加密密碼,也就是一串沒有任何邏輯的字符,這串加密密碼採用的是單向加密算法進行加密,也就是說無法通過反向破解得到密碼,我想這也是早期會直接將加密密碼放在/etc/passwd的原因吧。如果我們生的再早個十幾年,就會直接在/etc/passwd中看到加密密碼了。
但是/etc/passwd這個文件在同一超級管理員下的各個賬戶裏是透明的,也就是說,誰都可以訪問到/etc/passwd這個文件並且獲取到那一串加密密碼。這樣有啥用,密碼不還是單向加密的嗎?儘管不可破解,但是仍然存在着根據用戶的身份等信息推測密碼經相同的加密處理後與原來的加密密碼進行對比從而獲取密碼的風險。爲了避免這種情況,現在的某些系統將加密密碼存放在一個shadow(陰影)文件中,並且給這個文件設置爲僅超級管理員可見,而/etc/passwd密碼的位置僅僅用一個'x'意思一下。這個shadow文件就是/etc/shadow.
mbl:$1$Y/1ISiCx$S5mv/6lKRM1ZobXdP8629LsI2DsNWJpkAUFiO8PlZTN741DoyI6cvOFQVGluS/dF7tCadfACwhbfcFt5v0iK9Y8bp:18307:0:99999:7:::
左邊第二個就是加密密碼所在位置,$1$Y/1ISiCx$S5mv/6lKRM1ZobXdP8629LsI2DsNWJpkAUFiO8PlZTN741DoyI6cvOFQVGluS/dF7tCadfACwhbfcFt5v0iK9Y8bp。前半部分的$1$Y/1ISiCx$是鹽值,從官方文檔中我們可以知道用戶密碼經過了glibc中的crypt算法的處理,處理後會形成鹽值後面的一串字符串,對於相同的密碼,哈希算法加密出來的字符串也相同,因此,鹽值的存在就是爲了區分這些相同密碼形成的相同加密碼 同時也爲破解增加了難度。
/etc/shadow中的各個信息被struct spwd這個結構體管理。感興趣可以瞭解一下。
有了/etc/shadow,安全性就大大提高。想要獲取加密密碼?得先知道超級管理員密碼。
如果可以成功的擼到crypt加密算法,下一節的內容就是crypt的算法實現了。
三,小福利
(1)先領略一下crypt的風采吧。
Python3:
C: 編譯的時候要帶上-lcrypt
(2)上面說到了/etc/passwd這個文件,自己編寫個程序輸出這裏面的內容吧
#include <pwd.h> #include <cstring> #include <cstdio> void printPwRecord(){ struct passwd *ptr = nullptr; setpwent(); while((ptr = getpwent()) != nullptr){ printf("%s:%s:%u:%u:%s:%s:%s\n", ptr->pw_name, ptr->pw_passwd, ptr->pw , ptr->pw_dir, ptr->pw_shell); } endpwent(); } int main(){ printPwRecord(); }
這段程序用到了三個函數,setpwent(); getpwent(); endpwent();
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwent(void);
void setpwent(void);
void endpwent(void);
這三個函數用於訪問password file,比如/etc/passwd.
getpwent函數返回文件的的下一個記錄項,setpwent函數定位到文件開始處,endpwent函數關閉這些文件。注意:在getpwent之前調用setpwent是自我保護性的措施,以便在調用者在此之前已經調用getpwent打開了有關文件的情況下,重新使他們定位到文件開始處。最後要調用endpwent關閉這些文件。
與passwd相關的還有getpwuid和getpwnam這兩個函數,
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwnam(const char *name);
struct passwd *getpwuid(uid_t uid);
分別通過用戶名/用戶id獲取該指定用戶的struct passwd結構體,通過這個結構體可以訪問該用戶信息。