一、实验目的
了解Linux下的用户管理机制,熟练掌握Linux下的C语言编程以及gcc工具的使用。
需要的知识:C/C++语言的基本技能、第9章用户管理知识、第12章gcc的使用。
二、实验内容
Linux系统管理的一项重要工作就是用户管理。用户的口令以加密的形式存储在口令文件/etc/shadow中。弱口令就是很容易被猜出来的口令,比如与用户名相同的口令、像“123456、admin、computer”这类常用的口令等,口令字典是指将一些常用弱口令写在一个文本文件。管理员应该定期检测系统中是否存在弱口令。试编写一个c语言程序,主动检查自己的Linux系统中是否存在弱口令。
三、实验步骤
步骤1:分析/etc/shadow文件的格式。
可以查看自己的系统中该文件的格式,参照9.1节的介绍,该文件的每一行对应一个用户,下面是一个系统中/etc/shadow文件的实例:
user1:$6$DVLiBPZG$IrR9o0KpjtGQOj7I5WvgxQ.jMQ/Qzl3cJp4w0loUMZs4xQSQ8wkdIK7Sdkdk2pMXeAfOYq9O07r/QuDdJ8f3c0:14748:0:99999:7:::
user2:$6$RR8pmW2aerqIkySA$PcMV7/Z37QFCe9hJrf1rlUjPTAOdmKsW/mfG40V343kxG1QNsWWI7mdzl.50SCJpI4TQ/x4z4zsCoiA48EjAn1:14748:0:99999:7:::
user3:$6$oGG.739y$9ysybZ.VaTQ7dmR1zyz1vR8OiCUSCnzqnFd1PUYvedJMt.t6ElISwUohtOAlqAuT7.sPDjfy.bKCKar82mSp2.:14748:0:99999:7:::
user4:$6$AJerec5o$bwgJnQ0mTPzZMRCZYuivQVsWtD9mlh3.pWK2tR2pZPr4NzSlqk6hhFq3/zfWJXQCNmXJTlZhubwwW9x6a8mtM0:14748:0:99999:7:::
user5:$6$o1DA6WOiXtme7Zsw$Lj6bXgI5c5Kg/GewGWYv.4pQ0fD/AnSYEjMvmXxuvzEK3IYhNYjnTIEnTPQr9pZIMzatBOyrC4FgBjYtR5R.n1:14749:0:99999:7:::
user6:$6$UUXC4WKX$mKyl/32n7xrU1ChPIJYs2gwYuEoObdkNsPcVhxR22xFBIspNjVIfRv4FgoDWsJIxy4TZ.ci70MeDvDMEeExXL0:14749:0:99999:7:::
步骤2:了解Linux下口令加密的原理
口令的加密是使用Linux系统的crypt函数。使用info或者man可以了解该命令的工作原理:Red Hat Linux9中使用的MD5算法,在Fedora 10中默认使用了SHA-512算法。它使用一个字符串作为salt(翻译成盐),长度是8到16个字节,将用户输入的口令key进行加密。函数crypt(key,salt)的结果存入/etc/shadow文件的第2个域。这个域前面$6$salt$就是crypt函数的salt参数。当给用户设置口令时,salt是由系统随机选取的,因此即使是相同的key,因salt不同而第二个域的值也不同。
当用户在登录中输入自己的口令时,系统使用crypt进行同样的计算,如果所得的结果与/etc/shadow中存储的一致,则接受用户的登录。
步骤3:什么是弱口令:弱口令就是很容易被猜出来的口令,比如admin,guest,flower,123456,beauty等等。在口令猜测或者破解时,一般不会穷尽所有字符的所有排列组合,一般都使用一个弱口令字典,字典中包含了常被用来作为口令的字符串。可以到网上查找口令字典。
步骤4:弱口令检查的原理
对每个用户而言,逐个将那些经常被用来作为口令的词,使用crypt做运算,如果运算结果与/etc/shadow所存储的加密后的口令相同,则口令被猜出来。
步骤5:用c语言编写实现口令检查的程序
关键部分的代码如下:
通过读取/etc/shadow的每一行,获得一个关于用户的数据结构,存放在pwd中。
char saltstr[21]; //存放种子,最多是20个字节
bzero(saltstr,sizeof(saltstr));//将变了全部清0
strncpy(saltstr,pwd->pw_passwd,20);
//将salt取出,最多20个字节,以其中$作为边界
cp = crypt (guess, saltstr); //调用crypt加密函数
if (strcmp (cp, pwd -> pw_passwd)) //与口令文件中存储的信息比较
return (0); //若不一致则返回
printf ("Warning! Password Problem: Guessed:\t%s\tpasswd: %s\n",
pwd -> pw_name, guess); //找到口令,显示口令
步骤6:编译程序
gcc –o passchk pass.c –lcrypt
其中-o选项指定编译后的可执行文件名,-l选项表示使用crypt函数库
步骤7:执行口令检查程序
./passchk –P myshadow –w words –p
其中passchk是可执行文件名,myshadow是口令文件,如果没有-P选项,则缺省使用Linux系统的/etc/shadow文件,words是存放弱口令的口令字典文件,选项-p表示将破解后的口令输出。
四、实验结果
1、将/etc/shadow拷贝到myshadow
2、编辑口令字典words
3、编译程序
4、运行程序
#include
#include
#include
int main(int args, char* argv[]){
char* dir1;
char* dir2;
int flag = 0;
for(int i = 0; i < args; i++){
if(argv[i][0] == '-'){
if(argv[i][1] == 'P'){
dir1 = argv[i + 1];
flag = 1;
}
if(argv[i][1] == 'w'){
dir2 = argv[i + 1];
}
}
}
FILE* myshadow;
if(flag) myshadow = fopen(dir1, "r");
else myshadow = fopen("/etc/shadow", "r");
char buf1[500];
char buf2[500];
int index[5];
while(!feof(myshadow)){
fgets(buf1, 500, myshadow);
if(feof(myshadow)) break;
int count = 0, flag = 1;
for(int i = 0; i < strlen(buf1) && count < 5; i++){
if(buf1[i] == ':' || buf1[i] == '$'){
index[count++] = i;
if(buf1[i] == '$') flag = 0;
}
}
if(flag) continue;
FILE* words = fopen(dir2, "r");
while(!feof(words)){
fgets(buf2, 500, words);
if(buf2[strlen(buf2) - 1] == '\n') buf2[strlen(buf2) - 1] = '\0';
char salt[50];
char psw[500];
char name[50];
bzero(salt, sizeof(salt));
bzero(psw, sizeof(psw));
bzero(name, sizeof(name));
strncpy(salt, buf1 + index[0] + 1, index[3] - index[1] + 1);
strncpy(psw, buf1 + index[0] + 1, index[4] - index[1]);
strncpy(name, buf1, index[0]);
char* cp = crypt(buf2, salt);
if(strcmp(cp, psw) == 0){
printf("Warning! Password Problem: Guessed:\t%s\tpasswd: %s\n", name, buf2);
break;
}
}
fclose(words);
}
fclose(myshadow);
return 0;
}
//大吉大利,今晚AC