linux的PAM認證和shadow檔案中密碼的加密方式

來源:互聯網
上載者:User

PAM全稱是:Pluggable Authentication Modules,中文叫“可插入認證模組”。
它是一種統一的認證方案。PAM 讓您能隨時改變您的認證方法以及需求,並且不需要重新編譯任何代碼就封裝了所有本地認證方法。具體見
PAM 網站。

對於 PAM 您只需要做:

  • 對您的密碼採用不同於 DES 的加密方式(讓它們面對暴力解碼(brute-force decode)時更為堅固)。

  • 對您所有使用者使用資源限額,以防止他們進行拒絕服務(denial-of-service)攻擊(進程數、佔用記憶體量等等)。

  • 隨時啟用 shadow password (見下文)

  • 只在特定的時間允許特定的使用者從特定的地方登入

上述介紹來源於http://man.ddvip.com/linux/Mandrakelinux10server/password-security.html。

========================================

我們看看shadow檔案的格式:
root@localhost:~# cat /etc/shadow
root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:14838:0:99999:7:::
daemon:*:14838:0:99999:7:::
bin:*:14838:0:99999:7:::
sys:*:14838:0:99999:7:::
sync:*:14838:0:99999:7:::
games:*:14838:0:99999:7:::
man:*:14838:0:99999:7:::
lp:*:14838:0:99999:7:::
mail:*:14838:0:99999:7:::
news:*:14838:0:99999:7:::
uucp:*:14838:0:99999:7:::
proxy:*:14838:0:99999:7:::
www-data:*:14838:0:99999:7:::
backup:*:14838:0:99999:7:::
list:*:14838:0:99999:7:::
irc:*:14838:0:99999:7:::
gnats:*:14838:0:99999:7:::
nobody:*:14838:0:99999:7:::
libuuid:!:14838:0:99999:7:::
Debian-exim:!:14838:0:99999:7:::
statd:*:14838:0:99999:7:::
sshd:*:14838:0:99999:7:::
test::14879:0:99999:7:::
格式是:
{使用者名稱}:{加密後的密碼字串}:{口令最後修改時間距1970年1月1日的天數}:{ 口令能被修改之前的天數(防止修改口令,然後立刻將它改回到老口令)}:{口令必須被修改之後的天數}:{口令期滿前的天數}:{口令期滿後的天數}:{保留}
shadow是個可讀檔案,普通使用者沒有讀寫權限,超級使用者權限為可讀寫。

如果密碼字串為*,表示系統使用者不能被登入,為!表示使用者名稱被禁用,如果密碼字串為空白,表示沒有密碼,通過passwd -d 使用者名稱 可以清空一個使用者的口令。

具體shadow可參考shadow how-to,儘管這是一份已經過時了的文檔。

下面探討下shadow中的密碼加密問題:

還是以上面的root使用者為例:
root:$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.:14838:0:99999:7:::
其中的密碼域為$1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF. ,參考linux標準的passwd.c源檔案,在pw_encrypt函數中可以找到加密方法:
 40 char *pw_encrypt (const char *clear, const char *salt)
41 {
42     static char cipher[128];
43     char *cp;
44
45     cp = crypt (clear, salt);
46     if (!cp) {
47         /*
48          * Single Unix Spec: crypt() may return a null pointer,
49          * and set errno to indicate an error.  The caller doesn't
50          * expect us to return NULL, so...
51          */
52         perror ("crypt");
53         exit (1);
54     }
55
56     /* The GNU crypt does not return NULL if the algorithm is not
57      * supported, and return a DES encrypted password. */
58     if (salt && salt[0] == '$' && strlen (cp) <= 13)
59     {
..........
79         fprintf (stderr,
80              _("crypt method not supported by libcrypt? (%s)\n"),
81               method);
82         exit (1);
83     }
84
85     if (strlen (cp) != 13)
86         return cp;  /* nonstandard crypt() in libc, better bail out */
87     strcpy (cipher, cp);
88
89     return cipher;
90 } 

也就是說加密用純文字密碼和一個叫salt的東西用crypt()加密產生密文。
再來看看crypt的協助:
http://www.kernel.org/doc/man-pages/online/pages/man3/crypt.3.html
可發現原來crypt密文裡是由三部分組成的,即:$id$salt$encrypted
目前常用的是當id為1時,使用md5加密,id為5,採用SHA256進行加密,id為6採用SHA512進行加密。
分析上面的函數,可看出我們的shadow密碼中,直接把$id$salt$encrypted 當做salt參數帶入進行crypt加密。
那好,我們可以寫個簡短的代碼進行實驗:
#include <pwd.h>
#include <stddef.h>
#include <string.h>
#include <shadow.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
if(argc < 2)
{
printf("no usrname input");
return 1;
}
if (geteuid() != 0)
fprintf(stderr, "must be setuid root");
struct passwd *pwd;
pwd = getpwnam(argv[1]);
if(pwd ==NULL)
printf("no username found.\n");
else
{
printf("passwd: %s\n", pwd->pw_passwd);
if(strcmp(pwd->pw_passwd, "x") == 0)
{
printf("shadow used.\n");
struct spwd *shd= getspnam(argv[1]);
if(shd != NULL)
{
static char crypt_char[80];
strcpy(crypt_char, shd->sp_pwdp);
char salt[13];
int i=0,j=0;
while(shd->sp_pwdp[i]!='\0'){
salt[i]=shd->sp_pwdp[i];
if(salt[i]=='$'){
j++;
if(j==3){
salt[i+1]='\0';
break;
}
}
i++;
}
if(j<3)perror("file error or user cannot use.");
if(argc==3)
printf("salt: %s, crypt: %s\n", salt, crypt(argv[2], salt));
printf("shadowd passwd: %s\n", shd->sp_pwdp);
}
}
}
return 0;
}

儲存後執行gcc passwd.c -lcrypt -o passwd

編譯成功後運行./passwd root 123
其中./passwd是產生的命令,root是我們用來測試的賬戶,123是測試系統中root使用者的密碼,執行的結果是:
passwd: x
shadow used.
salt: $1$Bg1H/4mz$, crypt: $1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.
shadowd passwd: $1$Bg1H/4mz$X89TqH7tpi9dX1B9j5YsF.
可見,我們得到了和系統shadow檔案下相同結果的密文。

根據我們的運行結果我們可以看到,在root使用者的shadow中,他的salt是$1$Bg1H/4mz$
我們之前也是用這個salt來進行加密匹配的。但是,問題是:這個salt到底是怎麼來的??

還是分析標準的passwd.c,
在passwd.c中,找到了產生salt的函數:crypt_make_salt
201 char *crypt_make_salt (const char *meth, void *arg)
202 {
203     /* Max result size for the SHA methods:
204      *  +3      $5$
205      *  +17     rounds=999999999$
206      *  +16     salt
207      *  +1      \0
208      */
209     static char result[40];
210     size_t salt_len = 8;
211     const char *method;
212
213     result[0] = '\0';
214
215     if (NULL != meth)
216         method = meth;
217     else {
218     if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL)
219         method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
220     }
221
222     if (!strcmp (method, "MD5")) {
223         MAGNUM(result, '1');

224 #ifdef USE_SHA_CRYPT
225     } else if (!strcmp (method, "SHA256")) {
226         MAGNUM(result, '5');
227         strcat(result, SHA_salt_rounds((int *)arg));
228         salt_len = SHA_salt_size();
229     } else if (!strcmp (method, "SHA512")) {
230         MAGNUM(result, '6');
231         strcat(result, SHA_salt_rounds((int *)arg));
232         salt_len = SHA_salt_size();
233 #endif
234     } else if (0 != strcmp (method, "DES")) {
235         fprintf (stderr,
236              _("Invalid ENCRYPT_METHOD value: '%s'.\n"
237                "Defaulting to DES.\n"),
238              method);
239         result[0] = '\0';
240     }
241
242     /*
243      * Concatenate a pseudo random salt.
244      */
245     assert (sizeof (result) > strlen (result) + salt_len);
246     strncat (result, gensalt (salt_len),
247          sizeof (result) - strlen (result) - 1);
248
249     return result;
250 }
除了一大段條件判斷語句,其實最重要的只有一句gensalt(salt_len)。
看看gensalt的定義:
167                                                                                                                                                                   
168 static char *gensalt (unsigned int salt_size)
169 {
170     static char salt[32];
171
172     salt[0] = '\0';
173
174     assert (salt_size >= MIN_SALT_SIZE &&
175             salt_size <= MAX_SALT_SIZE);
176     seedRNG ();
177     strcat (salt, l64a (random()));
178     do {
179         strcat (salt, l64a (random()));
180     } while (strlen (salt) < salt_size);
181     salt[salt_size] = '\0';
182
183     return salt;
184 }
哦,原來神秘的salt只是某個的固定長度的隨機的可見的字串而已。
每次改寫密碼時,都會再隨機產生一個這樣的salt。而使用者登入時,會拿使用者登入的純文字密碼經過上述示範的步驟產生密文後和shadow裡的密碼域進行比較。

有了上述的分析,要暴利破解linux下的口令也不是什麼問題,但前提是你有機會拿到shadow檔案,這個前提條件貌似很難。
本文只是篇技術分析文章,沒有其它任何初衷。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.