1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| #!/usr/bin/env python3
| # 弱口令自查:拿一批常见弱口令去撞 talent_card 库里所有 password_hash。
| #
| # 算法与 MerchantPasswordHasher 一致:PBKDF2WithHmacSHA256(possword, salt, iterations, 256bit)
| # 存储格式:pbkdf2$<iterations>$<base64 salt>$<base64 derived>
| #
| # 只打印命中的账号名,不打印哈希值。
| # 用法:python3 /root/check-weak-passwords.py
|
| import base64
| import hashlib
| import subprocess
| import sys
|
| CANDIDATES = [
| "123456", "1234567", "12345678", "123456789", "1234567890", "123456789a", "a123456789",
| "a123456", "123456a", "abc123", "123abc", "abc123456", "Aa123456", "Aa123456.", "Aa123456789",
| "111111", "000000", "666666", "888888", "112233", "123123", "123321", "654321", "5201314",
| "woaini1314", "qwerty", "qwerty123", "1qaz2wsx", "1q2w3e4r", "zxcvbnm", "qwe123",
| "admin", "admin123", "admin888", "admin@123", "Admin@123", "admin123456", "administrator",
| "root", "root123", "toor", "password", "password123", "passw0rd", "P@ssw0rd", "P@ssword123",
| "letmein", "welcome", "iloveyou", "monkey", "dragon",
| "test", "test123", "test@123", "Test@123", "demo123",
| "talentcard", "talent_card", "talent-card", "card123", "rencaika", "rc123456", "pzh123456",
| "huifu123", "merchant123", "shop123", "88888888", "168168", "666888",
| ]
|
| TABLES = ("admin_operator", "merchant_operator")
|
|
| def derive(password, encoded):
| parts = encoded.split("$")
| if len(parts) != 4 or parts[0] != "pbkdf2":
| return None
| iterations = int(parts[1])
| salt = base64.b64decode(parts[2])
| expected = base64.b64decode(parts[3])
| got = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, iterations, dklen=len(expected))
| return got == expected
|
|
| def rows_for(table):
| sql = "select id, account, password_hash from " + table
| out = subprocess.run(["mysql", "-N", "-B", "-D", "talent_card", "-e", sql],
| capture_output=True, text=True)
| if out.returncode != 0:
| print(" (跳过 " + table + ":" + out.stderr.strip().splitlines()[0] + ")")
| return []
| return [line.split("\t") for line in out.stdout.strip().splitlines() if line]
|
|
| def main():
| accounts = []
| for table in TABLES:
| for row in rows_for(table):
| accounts.append((table, row[0], row[1], row[2]))
|
| print("待检账号 " + str(len(accounts)) + " 个;候选弱口令 " + str(len(CANDIDATES)) + " 个")
| hits = 0
| for table, rid, account, encoded in accounts:
| matched = [c for c in CANDIDATES if derive(c, encoded) is True]
| if matched:
| hits += 1
| print("[命中] " + table + " id=" + rid + " account=" + account + " -> " + str(matched))
| if hits == 0:
| print("结论:没有任何账号命中这批常见弱口令。")
| else:
| print("结论:有 " + str(hits) + " 个账号仍是弱口令,必须改。")
| return 0 if hits == 0 else 1
|
|
| if __name__ == "__main__":
| sys.exit(main())
|
|