I'd like to prove to a friend of mine that his wifi is insecure and learn something about password cracking on the way. The guy I am talking about does not believe in strong passwords but in SSID hiding and mac address filtering. As you know this is bad.

What I can already do is logging in with a known password after discovering the SSID and spoofing a valid MAC address. But to really show him a good password is needed I'd like to crack an unknown one.

So here is my actual question: I'd like to use hashcat (for the first time) to do the heavy liftig. Are there any settings or rulesets that will optimize cracking a password created by a German? I know of course that I should use German (pass-)wordlists and dictionaries. But apart from that?

I googled and checked the hashcat forum. The results I found were about German Umlauts. I think this won't be a problem as a PSK is saved by the router which will - most likely UTF-8. Is that correct? Are there other things I need to consider like special rulesets or something?

Thanks for your help! Any hint is appreciated. Dirk

up vote 5 down vote accepted

(This thread is cross-posted on the hashcat forums here. My answer there was too simplistic, so I'll try to do a better job here.)

The basics

For wordlists and rules, it sounds like you've already got the basics down. As long as the wordlists are in UTF-8, and the input method used to set the password is also UTF-8, then they should work well. I would definitely pursue wordlists and rules first, because raw bruteforce will take more time than the basic attacks, and WPA/WPA2 is such a "slow" (hard to crack) hash.

The basics of password cracking are already well covered elswhere. Here are some useful howtos (but note that if your target password contains at least one German character, only the wordlist and rule-based techniques will apply to your situation):

These overviews should help to fill in any gaps in your basic techniques.

Bruteforce of UTF-8 (mixed single-byte and multibyte), part 1 - simple proof of concept

If you do want to pursue bruteforce, you will need to do a little more work, because of how hashcat works under the hood. For cracking purposes, hashcat treats everything as a series of bytes. The German-specific UTF-8 characters are multibyte - represented in UTF-8 with more than one byte.

To bruteforce multibyte, you can specify character sets using the --hex-charset parameter, and use the technique described in this related post from the hashcat forums, which uses masks to simulate bruteforce for multibyte characters.

However, the technique in that post assumes that the charsets are entirely multibyte. German is different, in that only some of the characters are multibyte. Any German word that uses German-specific characters is actually a mix of one-byte-wide and two-byte-wide characters, and hashcat does not distinguish between the two.

So that technique has to be adapted somewhat. I'll briefly cover how here. I use MD5 for simplicity; WPA/WPA2 should work exactly the same (just much slower).

First, we must determine the hex values that will be used in the password mask. An easy way to do this is to create a file that lists the UTF-8 form of all non-ASCII characters that are likely to appear in your passwords, and then show their hex equivalents:

$ for item in `cat german.list`; do echo -e "$item: "; echo -n "$item" | xxd -p; done
Ä: c384
ä: c3a4
É: c389
é: c3a9
Ö: c396
ö: c3b6
Ü: c39c
ü: c3bc
ß: c39f

I'm not familiar with German, but these characters clearly have 'c3' as their first byte. (This is because they are all in the same Unicode block - specifically, the Latin-1 Supplement block). So since all expected multibyte characters will have this byte as a "prefix", we will start with that, and then append all of the "second bytes" using hashcat's custom mask parameters.

Here's a simple walkthrough.

First, we capture our plaintext (using '-n' to ensure that no line breaks are at the end of the string):

$ echo -n 'schön5' >german.plain

Next, we show that the string actually contains the expected two-byte sequence 'c3b6' where we expect it:

$ cat german.plain | xxd -p
736368c3b66e35

Next, we get the MD5 hash of that plain:

$ cat german.plain | md5sum | awk '{print $1}' | tee german.hash
bbf9ee923fe21c044838865c7acf530d

Finally, we run hashcat:

$ ./hashcat -m 0 -a 3 --hex-charset -1 c3 -2 8489969c9fa4a9b6bc german.hash ?a?a?a?1?2?a?a

... with flags explained as follows:

  • -m 0 (hash mode 0 - MD5)

  • -a 3 (attack mode 3 - bruteforce)

  • --hex-charset, to allow specifying hex charsets

  • -1, the first custom character set (the 'c3' prefix)

  • -2, the second custom character set (all of the second bytes from our German characters, "8489969c9fa4a9b6bc")

  • german.hash (our target hash)

  • a?a?a?1?2?a?a (a simple mask containing all printable 7-bit ASCII (?a) in most positions, and '?1?2' in the "fourth" position)

The command produces this output, showing that we have successfully cracked our target hash:

hashcat (v3.40-73-g99fbaa8) starting...

[informational hashcat output snipped]

INFO: approaching final keyspace, workload adjusted

bbf9ee923fe21c044838865c7acf530d:schön5

Session..........: hashtest
Status...........: Cracked
Hash.Type........: MD5
Hash.Target......: bbf9ee923fe21c044838865c7acf530d
Time.Started.....: Sun Mar 26 08:46:08 2017 (0 secs)
Time.Estimated...: Sun Mar 26 08:46:08 2017 (0 secs)
Guess.Mask.......: ?a?a?a?1?2?a?a [7]
Guess.Charset....: -1 c3, -2 8489969c9fa4a9b6bc, -3 Undefined, -4 Undefined
Guess.Queue......: 1/1 (100.00%)
Speed.Dev.#1.....:  9411.3 MH/s (0.18ms)
Speed.Dev.#2.....:  9896.7 MH/s (0.18ms)
Speed.Dev.#3.....:  4829.7 MH/s (0.27ms)
Speed.Dev.#4.....:  5154.5 MH/s (0.27ms)
Speed.Dev.#5.....:  4555.7 MH/s (0.27ms)
Speed.Dev.#6.....:  4747.7 MH/s (0.27ms)
Speed.Dev.#*.....: 38595.5 MH/s
Recovered........: 1/1 (100.00%) Digests, 1/1 (100.00%) Salts
Progress.........: 902162052/69640284375 (1.30%)
Rejected.........: 0/902162052 (0.00%)
Restore.Point....: 0/81225 (0.00%)
Candidates.#1....: "yaÄ 1 -> }baü]a
Candidates.#2....: w!cÜ'p -> JWAÖe&
Candidates.#3....: {kaÄ^) -> psaÖ'p
Candidates.#4....: FUSÜe& -> Q!cä.+
Candidates.#5....: @loé.+ -> &11üV<
Candidates.#6....: /11ÄW~ -> :enü~}
HWMon.Dev.#1.....: Temp: 51c Fan: 34% Util: 63% Core:1898MHz Mem:4513MHz Bus:8
HWMon.Dev.#2.....: Temp: 49c Fan: 32% Util: 50% Core:1860MHz Mem:4513MHz Bus:4
HWMon.Dev.#3.....: Temp: 63c Fan:  3% Util: 96% Core:1354MHz Mem:3004MHz Bus:16
HWMon.Dev.#4.....: Temp: 62c Fan:  1% Util:100% Core:1366MHz Mem:3004MHz Bus:4
HWMon.Dev.#5.....: Temp: 65c Fan:  2% Util:100% Core:1379MHz Mem:3004MHz Bus:1
HWMon.Dev.#6.....: Temp: 66c Fan:  3% Util: 97% Core:1366MHz Mem:3004MHz Bus:1

Started: Sun Mar 26 08:45:52 2017
Stopped: Sun Mar 26 08:46:10 2017

Bruteforce of UTF-8, part 2 - with mask coverage

The simple demonstration above shows that the '?1?2' technique works ... but it also presumes that you know exactly which characters are German. In the real world, we usually do not know this.

Instead, rather than using a single mask, you'll need to supply a file that contains a list of all of the masks that cover the length of password that you want to try. Here's an example of a mask file that covers all six-character words that contain at least one 7-bit ASCII equivalent character (?a) and other characters from German using our multibyte mask pairs (?1?2), in all positions:

$ cat utf8.hcmask.6char
?a?a?a?a?a?1?2
?a?a?a?a?1?2?a
?a?a?a?a?1?2?1?2
?a?a?a?1?2?a?a
?a?a?a?1?2?a?1?2
?a?a?a?1?2?1?2?a
?a?a?a?1?2?1?2?1?2
?a?a?1?2?a?a?a
?a?a?1?2?a?a?1?2
?a?a?1?2?a?1?2?a
?a?a?1?2?a?1?2?1?2
?a?a?1?2?1?2?a?a
?a?a?1?2?1?2?a?1?2
?a?a?1?2?1?2?1?2?a
?a?a?1?2?1?2?1?2?1?2
?a?1?2?a?a?a?a
?a?1?2?a?a?a?1?2
?a?1?2?a?a?1?2?a
?a?1?2?a?a?1?2?1?2
?a?1?2?a?1?2?a?a
?a?1?2?a?1?2?a?1?2
?a?1?2?a?1?2?1?2?a
?a?1?2?a?1?2?1?2?1?2
?a?1?2?1?2?a?a?a
?a?1?2?1?2?a?a?1?2
?a?1?2?1?2?a?1?2?a
?a?1?2?1?2?a?1?2?1?2
?a?1?2?1?2?1?2?a?a
?a?1?2?1?2?1?2?a?1?2
?a?1?2?1?2?1?2?1?2?a
?a?1?2?1?2?1?2?1?2?1?2
?1?2?a?a?a?a?a
?1?2?a?a?a?a?1?2
?1?2?a?a?a?1?2?a
?1?2?a?a?a?1?2?1?2
?1?2?a?a?1?2?a?a
?1?2?a?a?1?2?a?1?2
?1?2?a?a?1?2?1?2?a
?1?2?a?a?1?2?1?2?1?2
?1?2?a?1?2?a?a?a
?1?2?a?1?2?a?a?1?2
?1?2?a?1?2?a?1?2?a
?1?2?a?1?2?a?1?2?1?2
?1?2?a?1?2?1?2?a?a
?1?2?a?1?2?1?2?a?1?2
?1?2?a?1?2?1?2?1?2?a
?1?2?a?1?2?1?2?1?2?1?2
?1?2?1?2?a?a?a?a
?1?2?1?2?a?a?a?1?2
?1?2?1?2?a?a?1?2?a
?1?2?1?2?a?a?1?2?1?2
?1?2?1?2?a?1?2?a?a
?1?2?1?2?a?1?2?a?1?2
?1?2?1?2?a?1?2?1?2?a
?1?2?1?2?a?1?2?1?2?1?2
?1?2?1?2?1?2?a?a?a
?1?2?1?2?1?2?a?a?1?2
?1?2?1?2?1?2?a?1?2?a
?1?2?1?2?1?2?a?1?2?1?2
?1?2?1?2?1?2?1?2?a?a
?1?2?1?2?1?2?1?2?a?1?2
?1?2?1?2?1?2?1?2?1?2?a
?1?2?1?2?1?2?1?2?1?2?1?2

To generate the rest of the masks that you need, policygen from the PACK toolkit (Python) can help. It doesn't recognize how to make all permutations of '?1?2', but you can create masks that use a different character set (like ?u), and then replace all '?u' with '?1?2'.

As I said above, it's not for the faint of heart! But once you get the hang of it, it's not hard.

Non-UTF-8 character sets (rare for WPA/WPA2?)

If the characters are not UTF-8, the charsets that hashcat ships with can be used directly. They are in the ./charsets/ directory of the hashcat distribution, and their use is straightforward and common for non-Latin character sets.

That being said, I would expect non-UTF-8 character sets to be rare for WPA/WPA2 passphrases.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.