[Pentesting][Math] Finding masks for Hashcat using combinatorics

Let's analyze masks of popular 'rockyou' passwords lists. What are some common masks?

#!/usr/bin/env python3

import sys

def char_to_mask(c):
    if c>='0' and c<='9':
        return 'd'
    if c>='a' and c<='z':
        return 'l'
    if c>='A' and c<='Z':
        return 'u'

    return 's'

f=open("rockyou.txt", "rt", encoding="cp866")
for l in f:
    l=l.rstrip()
    print ("".join(map(char_to_mask, list(l))))
f.close()
./analyze.py | sort | uniq -c | sort -rn

Most popular masks:

 688032 llllllll
 601242 llllll
 585079 lllllll
 516853 lllllllll
 487432 ddddddd
 478213 dddddddddd
 428303 dddddddd
 420321 lllllldd
 416957 llllllllll
 390539 dddddd
 307538 ddddddddd
 292313 llllldd
 273633 llllllldd
 267737 lllllllllll
 235361 lllldddd
 215075 lllldd
 213113 lllllllldd
 193101 lllllld
 189849 llllllld
 189360 llllllllllll
 178306 llldddd
 173559 llllldddd
 160596 lllllldddd
 160055 lllllllld
 152403 lllllddd
 132219 llllllddd
 129829 llllllllld
 125805 lllll
 119303 lllllllllllll
 114735 llllld
 111219 llllddd
 107864 ddddddddddd
...

In other words, popular masks are:

Psychologically, people groups these types together, which results in sequences of lowercase characters, uppercase, digits, special characters. We will also get all permutations of these groups:

#!/usr/bin/env python3

import itertools, sys

cmds=set()

def out_mask(mask):
    if (len(mask)/2 >= 8) and (len(mask)/2 <= 15):
        cmds.add ((f"hashcat -m 22000 hash.txt -a 3 \"{mask}\"", total))

for u in range(0, 11+1):
    for l in range(0, 11+1):
        for d in range(0, 12+1):
            for s in range(0, 5+1): # 33 chars
                total=1
                if l>0:
                    total*=26**l
                if u>0:
                    total*=26**u
                if d>0:
                    total*=10**d
                if s>0:
                    total*=33**s

                tmp=["?u"*u, "?l"*l, "?d"*d, "?s"*s]
                for i in list(itertools.permutations(tmp)):
                    out_mask("".join(list(i)))

import datetime as dt
# https://human-readable.readthedocs.io/en/latest/usage.html
import human_readable

def measure_speed(total):
    # wpa2. hashes per sec: NVIDIA RTX 4000 Ada
    # https://yurichev.com/blog/wifi/
    speed=759000
    seconds=total/speed
    delta=dt.timedelta(seconds=seconds)
    #return human_readable.precise_delta(delta)
    return human_readable.time_delta(delta)

for y in sorted(list(cmds), key=lambda x: x[1]):
    if y[1]<2e+12: # limit
        print (y[0], "# %1.2e, %s" % (y[1], measure_speed(y[1])))

Example masks, sorted by number of passwords:

hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?d?d" # 1.00e+08, 2 minutes
hashcat -m 22000 hash.txt -a 3 "?u?d?d?d?d?d?d?d" # 2.60e+08, 5 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?d?u" # 2.60e+08, 5 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?d?l" # 2.60e+08, 5 minutes
hashcat -m 22000 hash.txt -a 3 "?l?d?d?d?d?d?d?d" # 2.60e+08, 5 minutes
hashcat -m 22000 hash.txt -a 3 "?s?d?d?d?d?d?d?d" # 3.30e+08, 7 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?d?s" # 3.30e+08, 7 minutes
hashcat -m 22000 hash.txt -a 3 "?l?l?d?d?d?d?d?d" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?l?l" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?u?l?d?d?d?d?d?d" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?u?l" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?l?u" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?u?u?d?d?d?d?d?d" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?u?d?d?d?d?d?d?l" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?d?d?d?d?d?d?u?u" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?l?u?d?d?d?d?d?d" # 6.76e+08, 14 minutes
hashcat -m 22000 hash.txt -a 3 "?l?d?d?d?d?d?d?u" # 6.76e+08, 14 minutes
...

Time is calculated depending on RTX4000 ADA and WPA2 cracking mode.

Here are all masks (or commands) faster than 1 month.

Many passwords can be cracked using these masks.

(the post first published at 20251215.)


List of my other blog posts.

Subscribe to my news feed,

Some time ago (before 24-Mar-2025) there was Disqus JS script for comments. I dropped it --- it was so motley, distracting, animated, with too much ads. I never liked it. Also, comments din't appeared correctly (Disqus was buggy). Also, my blog is too chamberlike --- not many people write comments here. So I decided to switch to the model I once had at least in 2020 --- send me your comments by email (don't forget to include URL to this blog post) and I will copy&paste it here manually.

Let's party like it's ~1993-1996, in this ultimate, radical and uncompromisingly primitive pre-web1.0-style blog and website. This website is best viewed under lynx/links/elinks/w3m.