├── README.md
└── grafana2hashcat.py
/README.md:
--------------------------------------------------------------------------------
1 |
Grafana2Hashcat
2 | Grafana2Hashcat makes it easy to convert Grafana hashes to PBKDF2_HMAC_SHA256 format in order to facilitate password cracking using Hashcat.
3 |
4 | ## Introduction
5 |
6 | Grafana is a multi-platform open source analytics and interactive visualization web application. It provides charts, graphs, and alerts for the web when connected to supported data sources.
7 |
8 | During security assessments you might come across a Grafana database, and get ahold of the users password hash digests. By default, the Grafana hash digests are not in a format supported by popular password cracking tools, such as Hashcat. Grafana uses the PBKDF2_HMAC_SHA256 hashing algorithm, and stores the hash digests in hexadecimal, and the salt values in plaintext format in the database.
9 |
10 | This can be confirmed by taking a look directly at the responsible code:
11 | ```go
12 | // File: https://github.com/grafana/grafana/blob/f496c31018cdb5ecc8b3c30ea96a235a5bcf470a/pkg/util/encoding.go#L33-L37
13 | // Commit: https://github.com/grafana/grafana/commit/574553ec7bb5e61c6a362ceb9f28cc9e1c8f6f63
14 | [...]
15 |
16 | // EncodePassword encodes a password using PBKDF2.
17 | func EncodePassword(password string, salt string) (string, error) {
18 | newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
19 | return hex.EncodeToString(newPasswd), nil
20 | }
21 |
22 | [...]
23 | ```
24 |
25 | For example, the password `secret` with a [non-random] salt value of `pepper` is [transformed](https://play.golang.org/p/t2rzj87i_en) to the following entry in the Grafana database (bear in mind these are two separate columns in the DB):
26 |
27 | ```hex
28 | 3ad31dc57a7452c442f259cfff7aa61f2a6cea88ee634724ae146e221ae4e01c56c8bcbb3552310acd2fd746a396d2f99bf8,pepper
29 | ```
30 |
31 | Tools such as Hashcat, however, require the PBKDF2_HMAC_SHA256 hash digest in the following format:
32 |
33 | ```
34 | sha256:NumberOfIterations:Base64EncodedSalt:Base64EncodedDigest
35 | ```
36 |
37 | For example, the previously mentioned Grafana hash digest can be transformed in following Hashcat equivalent:
38 | ```
39 | sha256:10000:cGVwcGVy:OtMdxXp0UsRC8lnP/3qmHyps6ojuY0ckrhRuIhrk4BxWyLy7NVIxCs0v10ajltL5m/g=
40 | ```
41 |
42 | This entry can then be imported in Hashcat in order to start the password cracking process.
43 |
44 |
45 | ## Usage
46 | ```console
47 | usage: grafana2hashcat.py [-h] [-o outfile] hashes
48 |
49 | Convert Grafana hashes to Hashcat's PBKDF2_HMAC_SHA256 format.
50 |
51 | positional arguments:
52 | hashes Input file holding the Grafana hashes in the 'hash,salt' format.
53 |
54 | optional arguments:
55 | -h, --help show this help message and exit
56 | -o outfile Output filename to save the Hashcat's PBKDF2_HMAC_SHA256 hashes.
57 | Default is stdout.
58 | ```
59 |
60 | ### Example usage
61 |
62 | ```console
63 | user@host:~$ cat grafana_hashes.txt
64 | 3ad31dc57a7452c442f259cfff7aa61f2a6cea88ee634724ae146e221ae4e01c56c8bcbb3552310acd2fd746a396d2f99bf8,pepper
65 | 6ceeee16107218b057249050a03aab9d72baa6f31345b5ed20a1f56f20a35cfdc0f50e5b15c310151e851094f4e0a779bb28,pepper
66 | 8daf61545e7f9c9b1fe35e668425c15cdd4f101187c30ce7257e33cd0e94216abb05d5e2f73d28d4c98fcd9227536676c3e7,pepper
67 | ```
68 |
69 | ```console
70 | user@host:~$ python3 grafana2hashcat.py grafana_hashes.txt
71 |
72 | [+] Grafana2Hashcat
73 | [+] Reading Grafana hashes from: ./grafana_hashes.txt
74 | [+] Done! Read 3 hashes in total.
75 | [+] Converting hashes...
76 | [+] Converting hashes complete.
77 | [*] Outfile was not declared, printing output to stdout instead.
78 |
79 | sha256:10000:cGVwcGVy:OtMdxXp0UsRC8lnP/3qmHyps6ojuY0ckrhRuIhrk4BxWyLy7NVIxCs0v10ajltL5m/g=
80 | sha256:10000:cGVwcGVy:bO7uFhByGLBXJJBQoDqrnXK6pvMTRbXtIKH1byCjXP3A9Q5bFcMQFR6FEJT04Kd5uyg=
81 | sha256:10000:cGVwcGVy:ja9hVF5/nJsf415mhCXBXN1PEBGHwwznJX4zzQ6UIWq7BdXi9z0o1MmPzZInU2Z2w+c=
82 |
83 |
84 | [+] Now, you can run Hashcat with the following command, for example:
85 |
86 | hashcat -m 10900 hashcat_hashes.txt --wordlist wordlist.txt
87 | ```
88 |
--------------------------------------------------------------------------------
/grafana2hashcat.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | import argparse
3 | import base64
4 |
5 | """
6 | Name: Grafana2Hashcat
7 | Description: Convert Grafana hashes to Hashcat's PBKDF2_HMAC_SHA256 format.
8 | Author: github.com/iamaldi
9 | """
10 |
11 | parser = argparse.ArgumentParser(description='Convert Grafana hashes to Hashcat\'s PBKDF2_HMAC_SHA256 format.')
12 | parser.add_argument('hashes', help='Input file holding the Grafana hashes in the \'hash,salt\' format.')
13 | parser.add_argument('-o', metavar="outfile", help='Output filename to save the Hashcat\'s PBKDF2_HMAC_SHA256 hashes. Default is stdout.')
14 | args = parser.parse_args()
15 |
16 | HASHCAT_PBKDF2_HMAC_SHA256_FORMAT = "sha256:10000:base64_salt:base64_digest"
17 | hashcat_hashes = []
18 |
19 | def read_file(filename: str):
20 | f = open(filename, "r")
21 | hashes = f.readlines()
22 | f.close()
23 | return hashes
24 |
25 | def write_file(filename: str, hashcat_hashes: list):
26 | f = open(filename, "w")
27 | for hashcat_hash in hashcat_hashes:
28 | f.write(hashcat_hash + '\n')
29 | f.close()
30 |
31 | def convert_hash(line: str):
32 | grafana_hash = line.rstrip('\n').split(',') # remove trailing newline character and split at the comma delimiter
33 | grafana_digest = grafana_hash[0]
34 | grafana_salt = grafana_hash[1]
35 | base64_salt = base64.b64encode(grafana_salt.encode('utf-8'))
36 | base64_digest = base64.b64encode(bytearray.fromhex(grafana_digest))
37 |
38 | hashcat_hash = HASHCAT_PBKDF2_HMAC_SHA256_FORMAT.replace("base64_salt", base64_salt.decode('utf-8'))
39 | hashcat_hash = hashcat_hash.replace("base64_digest", base64_digest.decode('utf-8'))
40 | return hashcat_hash
41 |
42 | if __name__ == "__main__":
43 | print("\n[+] Grafana2Hashcat")
44 | print("[+] Reading Grafana hashes from: ", args.hashes)
45 | grafana_hashes = read_file(args.hashes)
46 | print("[+] Done! Read {total_hashes} hashes in total.".format(total_hashes = len(grafana_hashes)))
47 |
48 | print("[+] Converting hashes...")
49 | for grafana_hash in grafana_hashes:
50 | hashcat_hashes.append(convert_hash(grafana_hash))
51 |
52 | print("[+] Converting hashes complete.")
53 | if not args.o:
54 | print("[*] Outfile was not declared, printing output to stdout instead.\n")
55 | for entry in hashcat_hashes: print (entry)
56 | print("\n")
57 | else:
58 | print("[+] Writing output to '{outfile}' file.".format(outfile = args.o))
59 | write_file(args.o, hashcat_hashes)
60 |
61 | print("[+] Now, you can run Hashcat with the following command, for example:\n")
62 | print("hashcat -m 10900 hashcat_hashes.txt --wordlist wordlist.txt\n")
--------------------------------------------------------------------------------