├── 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") --------------------------------------------------------------------------------