Many of the CTFs I've been playing lately have a challenge around cracking passwords from Gitea instances. These CTFs often require you to dump the PBKDF2 password hashes (stored in SQLite) from Gitea, and then crack them using software like hashcat. However, hashcat doesn't natively support the specific format Gitea uses, which means I need to spend time splicing and converting output before I can use it. It's not incredibly difficult to do, but it's annoying and boring, and whenever I find things which are annoying and boring I look for ways to automate them. 🙂

I ended up writing a small tool, gitea2hashcat.py, to convert these hashes into a hashcat-compatible format.

Note

I submitted a PR upstream to the hashcat repo. When it's live, you should be able to find it in the tools folder in hashcat.

In the meantime, feel free to grab it from the tools folder of my hashcat fork.

hashcat/tools/gitea2hashcat.py · GitHub

Let's explore this a bit.

The Gitea Hash Format:

Gitea, by default, uses PBKDF2-HMAC-SHA256 (specifically, they have something called pbkdf2_v2 which is the same as pbkdf2_v1 but uses a higher iteration cost.) Gitea stores the salt and password hash as hex-encoded values within different colums in the database. However, hashcat expects a single string with base64-encoded segements. The combined format looks like this:

pbkdf2-sha256:$iterations:$salt:$hash

Where:

  • pbkdf2-sha256 identifies the hashing algorithm.
  • $iterations is the number of PBKDF2 iterations.
  • $salt is the base64-encoded salt used for the password.
  • $hash is the resulting base64-encoded PBKDF2 hash.

This format mismatch prevents direct use of Gitea's password hashes with hashcat, but it's trivial to overcome. You can query the fields you need (remembering to put the salt before the hash) and then use a bit of bash magic to reformat everything. Or...

Welcome gitea2hashcat.py

Because I've had to do this several times already, I wrote gitea2hashcat.py which takes the Gitea salt and hash as input, and outputs it in a hashcat-friendly format. You can query the salt and hash out of sqlite and pipe it directly into the script, or provide your input via command-line parameters. You don't even have to remember to put the salt and hash in the right order, as this script will order them for you.

Let's demonstate how to use this.

Assume we can query sqlite and find these values:

sqlite> select email,salt,passwd,passwd_hash_algo from user;
admin|f38b580638449075e4edb39d46f4b3e2|4b8c6297fb37feed46659121af08de38057bbe53d4225c880bcb634039ff96b8ea0391e1a5e34cf4f8a016c54a2d15c46f36|pbkdf2$50000$50

From here, we could pass the salt and hash along to the script as command-line parameter:

$ gitea2hashcat.py "f38b580638449075e4edb39d46f4b3e2|4b8c6297fb37feed46659121af08de38057bbe53d4225c880bcb634039ff96b8ea0391e1a5e34cf4f8a016c54a2d15c46f36"
[+] Run the output hashes through hashcat mode 10900 (PBKDF2-HMAC-SHA256)

sha256:50000:84tYBjhEkHXk7bOdRvSz4g==:S4xil/s3/u1GZZEhrwjeOAV7vlPUIlyIC8tjQDn/lrjqA5HhpeNM9PigFsVKLRXEbzY=

But we could even just dump the sql output right into the script:

$ sqlite3 gitea.db 'select salt,passwd from user;' | gitea2hashcat.py
[+] Run the output hashes through hashcat mode 10900 (PBKDF2-HMAC-SHA256)

sha256:50000:84tYBjhEkHXk7bOdRvSz4g==:S4xil/s3/u1GZZEhrwjeOAV7vlPUIlyIC8t

I tried to make this as flexible as possible. If you queried the hash before the salt, it will recognize this and properly order them for you.

$ sqlite3 gitea.db 'select passwd,salt from user;' | gitea2hashcat.py
[+] Run the output hashes through hashcat mode 10900 (PBKDF2-HMAC-SHA256)

sha256:50000:84tYBjhEkHXk7bOdRvSz4g==:S4xil/s3/u1GZZEhrwjeOAV7vlPUIlyIC8t

It's super easy.

Using the Converted Hashes with Hashcat:

Once you've converted the Gitea hashes, you can easily use them with hashcat:

$ hashcat -m 10900 hashes.txt rockyou.txt

Where:

  • -m 10900 specifies the hash mode for PBKDF2-HMAC-SHA256.
  • hashes.txt contains the converted hashes (one salt + hash combo per line).
  • rockyou.txt is your wordlist.

And that's a wrap!

I'm a firm believer in automating tedious tasks, and when I didn't see an existing solution for this Gitea hash conversion, I decided to create one.  gitea2hashcat.py is my contribution to the community, and I hope it proves as useful to others as it has been to me. Please use it responsibly.

Feel free to grab the tool here: hashcat/tools/gitea2hashcat.py · GitHub

Happy hacking!