(前面部分轉自網路做說明)
在linux中,口令檔案在/etc/passwd中,早期的這個檔案直接存放加密後的密碼,前兩位是"鹽"值,是一個隨機數,後面跟的是加密的密碼。為了安全,現在的linux都提供了 /etc/shadow這個影子檔案,密碼放在這個檔案裡面,並且是只有root可讀的。
下面來分析一下/etc/passwd檔案,他的每個條目有7個域,分別是名字:密碼:使用者id:組id:使用者資訊:主目錄:shell 例如:ynguo:x:509:510::/home/ynguo:/bin/bash
在利用了shadow檔案的情況下,密碼用一個x表示,普通使用者看不到任何密碼資訊。如果你仔細的看看這個檔案,會發現一些奇怪的使用者名稱,她們是系 統的預設帳號,預設帳號是攻擊者入侵的常用入口,因此一定要熟悉預設帳號,特別要注意密碼域是否為空白。下面簡單介紹一下這些預設帳號
adm擁有帳號檔案,起始目錄/var/adm通常包括記錄檔
bin擁有使用者命令的可執行檔
daemon用來執行系統守護進程
games用來玩遊戲
halt用來執行halt命令
lp擁有印表機後台列印檔案
mail擁有與郵件相關的進程和檔案
news擁有與usenet相關的進程和檔案
nobody被NFS(網路檔案系統)使用
shutdown執行shutdown命令
sync執行sync命令
uucp擁有uucp工具和檔案
傳統上,/etc/passwd檔案在很大範圍內是可讀的,因為許多應用程式需要用他來把UID轉換為使用者名稱。例如,如果不能訪問/etc/passwd,那麼ls -l命令將顯示UID而不是使用者名稱。但是使用口令猜測程式,具有加密口令的可讀/etc/passwd檔案有巨大的安全危險。所以出現了影子檔案/etc/shadow。
影子口令系統把口令檔案分成兩部分:/etc/passwd和/etc/shadow。影子口令檔案儲存加密的口令;/etc/passwd檔案中的密碼全部變成x。Shadow只能是root可讀,從而保證了安全。/etc/shadow檔案每一行的格式如下:
使用者名稱:加密口令:上一次修改的時間(從1970年1月1日起的天數):口令在兩次修改間的最小天數:口令修改之前向使用者發出警告的天數:口令終止後帳號被禁用的天數:從1970年1月1日起帳號被禁用的天數:保留網域。
例如:root:$1$t4sFPHBq$JXgSGgvkgBDD/D7FVVBBm0:11037:0:99999:7:-1:-1:1075498172
bin:*:11024:0:99999:7:::
daemon:*:11024:0:99999:7:::預設情況下,口令更新並不開啟。如果你的系統沒有啟動影子檔案,那麼運行pwconv程式。
####################
Added by iceknife on 20100601
####################
shadow採用DES加密方式,破解方式為暴力破解,可以採用字典攻擊:
比如:
username:$1$jMzjGK//$Do9jjAM9TqHVhkH3eSytT.:14576:0:99999:7:::
在這之前已經知道使用者名稱username的密碼為123456,那密碼是如何得來的呢
採用函數crypt(char* key, char* salt); 注意用-lcrypt連結
crypt() is the password encryption function. It is based on the Data
Encryption Standard algorithm with variations intended (among other
things) to discourage use of hardware implementations of a key search.
key is a user’s typed password.
salt is a two-character string chosen from the set [a–zA–Z0–9./]. This
string is used to perturb the algorithm in one of 4096 different ways.
在這裡 key=123456
salt=$1$jMzjGK//$
那麼crypt得出的結果為$1$jMzjGK//$Do9jjAM9TqHVhkH3eSytT.
一下是一段暴力破解的原始碼
/*
============================================================================
Name : descrack.c
Author : iceknife
Version :
Copyright : Your copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
char data[37] = "abcdefghijklmnopqrstuvwxyz0123456789";
char *goalPass = "$1$AAODv...$gXPqGkIO3Cu6dnclE";
char mypwd[10];
int minlen = 1; //min password length
int maxlen = 3; //max password length
void subgenerate(int index, int pwdlen)
{
if (index == pwdlen)
return;
int i;
for (i = 0; i < 36; i++)
{
mypwd[index] = data[i];
memset(mypwd + index + 1, data[0], pwdlen- index -1);
if (i != 0)
{
// printf("%s ",mypwd);
if (!strcmp(goalPass, crypt(mypwd, "$1$AAODv...$")))
{
printf("find password:%s", mypwd);
exit(0);
}
}
subgenerate(index + 1, pwdlen);
}
}
void generate(int pwdlen, int start, int end)
{
int i;
for (i = start; i < end; i++) // 多線程可分段
{
mypwd[0] = data[i];
memset(mypwd + 1, data[0], pwdlen-1); //填充長度
// printf("%s ",mypwd);
if (!strcmp(goalPass, crypt(mypwd, "$1$AAODv...$")))
{
printf("find password:%s", mypwd);
exit(0);
}
subgenerate(1, pwdlen);
}
}
int main()
{
char mypwd[10];
if (maxlen > 9) puts("max password length must little then 9");
int i,threadnum = 10;
for (i = minlen; i <= maxlen; i++)
{
printf("/npassword length:%d/n", i);
//password length
memset(mypwd, 0, 10);
generate(i,0,36); //留作多線程
}
puts("password not found");
return 0;
}