一、文件格式
1、/etc/passwd
通过man 5 passwd我们可知passwd文件为以下格式:
name:password:UID:GID:GECOS:directory:shell
[root@localhost ~]# cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
cmd | name | password | UID | GID | GECOS | directory | shell |
---|---|---|---|---|---|---|---|
用户名 | 密码 | 用户ID | 组ID | 备注 | 用户家目录 | 登录shell | |
root | x | 0 | 0 | root | /root | /bin/bash | |
useradd | -u | -g | -c | -d | -s | ||
usermod | -L/-U | -u | -g | -c | -d | -s |
- 由于/etc/passwd文件的权限为644,即-rw-r–r--,其它用户对此文件是可读的因此密码处使用占位符x替代,真正的密码保存在/etc/shadow文件中。
- usermod命令
-L 锁定密码不被修改,并在加密字段前加感叹号"!"
-U 解锁密码,删除加密字段感叹号"!"
2、/etc/shadow
那么我们通过man 5 shadow再来看/etc/shadow文件的格式:
login name | encrypted password | date of last password change | minimum password age | maximum password age | password warning period | password inactivity period | account expiration date | reserved field |
---|---|---|---|---|---|---|---|---|
登录名 | 加密密码 | 最后一次更改密码日期 | 改密后等多久才被允许再次改密 | 这些天后必须更改密码 | 密码警告时间段 | 密码过期后使用天数 | 账户过期日期 | 保留字段 |
[root@localhost ~]# cat /etc/shadow
root:$6$KG9EiMu4$5tGJaGMFeTxfM4Vg8GnqnaW6qK.tiX.okI9O4bzwJ7IHjWGpbSEezRX7XX2crCjhc.pQlPJtZaZwZE6XaR.lk0:18240:0:99999:7:::
bin:*:17110:0:99999:7:::
daemon:*:17110:0:99999:7:::
......
test:$6$PXuMZisM$uiJ3Q.HR9mj1C.nYpNH4niRWP45OqoB.Rujs2zK9Xn5mdfava75V3hKF2eeK8QknFc5bhtKBMAfFubqPC4vQ61:18240:0:99999:7:::
3、crypt
这里我们重点关注字段二encrypted password,通过man 3 crypt查看C标准库的解释得到如下信息:
函数原型
#define _XOPEN_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
char *crypt(const char *key, const char *salt);
加密密文结构
$id$salt$encrypted
$6$PXuMZisM$uiJ3Q.HR9mj1C.nYpNH4niRWP45OqoB.Rujs2zK9Xn5mdfava75V3hKF2eeK8QknFc5bhtKBMAfFubqPC4vQ61
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) |
二、问题与思考
1、已知一明文如何手动模拟系统生成密文?
- C语言验证
#include <unistd.h>
#include <stdio.h>
int main()
{
char *password = "123456";
char *salt = "$6$PXuMZisM";
printf("The crypt_passwd is: %s\n",crypt(password,salt));
return 0;
}
运行结果:
[root@localhost ~]# gcc -lcrypt passwd_test.c -o passwd_test
[root@localhost ~]# ./passwd_test
The crypt_passwd is: $6$PXuMZisM$uiJ3Q.HR9mj1C.nYpNH4niRWP45OqoB.Rujs2zK9Xn5mdfava75V3hKF2eeK8QknFc5bhtKBMAfFubqPC4vQ61
由此可见,在c语言中,char *crypt(const char *key, const char *salt);,此处的salt是密码的前半部分,即$id$salt$encrypted中的"$id$salt"
- openssl passwd 验证
root@redwand:~# openssl passwd -6 -salt PXuMZisM 123456
$6$PXuMZisM$uiJ3Q.HR9mj1C.nYpNH4niRWP45OqoB.Rujs2zK9Xn5mdfava75V3hKF2eeK8QknFc5bhtKBMAfFubqPC4vQ61
【补充20200418】
当用户输入密码123456,操作系统会从/etc/shadow文件中读取salt的值,然后用salt+123456生成一个hash值(如上),如果hash与/etc/shadow中存储的相同,则密码正确,通过验证。否则,密码错误,验证失败。同时,在生成密码时,操作系统会随机给出salt值,避免用户之间因为salt相同而猜出对方密码。如下
root@kali2020:~# openssl passwd -6 123456
$6$7RsEIEYnxJ1uxjM3$24xRefdZOdqq9jfrezDJGovFc6mDpHU3R.we4d5OPQQh0v/1qqI2cU/BbgXdPxjt2fRrpyV1.A.GXbFIo4eZq.
root@kali2020:~# openssl passwd -6 123456
$6$NQLGE48VFcP/88wd$w/yOFF.kkoEmK/gyv4N3vhDDTv6vTerxgZ38QP.45/Vjs0/PIgnmveXvC5XCbjMALlh45giYoQwTs/aFPDGpl0
root@kali2020:~# openssl passwd -6 123456
$6$2JjaGnmheSLGKfwV$OZp3s1NtBLjnro/SAdlcrdgxtFoP18UhS4ynSZ0e7F1PMeFIbmC3YG3bbrU1OoCHHhtIgHHPTDe1/dOSxBLY81
2、如果/etc/passwd和/etc/shadow中同时加入不同密码,系统会优先读取哪个?
将密码123456加密密文放在/etc/passwd的密码占位符,同时将654321加密密文放在/etc/shadow的密文位置,登录时系统输入123456可登录,654321不能登录,证明系统首先读取/etc/passwd中存储的密码。
3、当我们获取了密码密文,如何破解为明文密码?
可以将密码写到linux.txt文件中,字典文件为pass.txt,可以使用hashcat工具进行破解,执行下面命令。
hashcat64.exe -m 1800 .\linux.txt .\pass.txt
跑出如下结果:
Session..........: hashcat
Status...........: Cracked
Hash.Type........: sha512crypt $6$, SHA512 (Unix)
Hash.Target......: $6$PXuMZisM$uiJ3Q.HR9mj1C.nYpNH4niRWP45OqoB.Rujs2zK...C4vQ61
Time.Started.....: Fri Dec 20 10:35:12 2019 (0 secs)
Time.Estimated...: Fri Dec 20 10:35:12 2019 (0 secs)
Guess.Base.......: File (.\pass.txt)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 32 H/s (0.92ms) @ Accel:64 Loops:32 Thr:32 Vec:1
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 6/6 (100.00%)
Rejected.........: 0/6 (0.00%)
Restore.Point....: 0/6 (0.00%)
Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:4992-5000
Candidates.#1....: pass -> 123456
Hardware.Mon.#1..: Temp: 54c Util: 69% Core:1417MHz Mem:3504MHz Bus:16
可以看到hashtype为sha512crypt $6$, SHA512 (Unix),这里我们使用hashcat对应的-m 1800选项,对应破解相应密码,破解结果会保存在同级目录的hashcat.potfile文件中。