Unpublished WPA key algorithms

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
Yep, indeed a very similar (but much easier) calculation from the PIN. Looks like the PIN is based on the number of seconds since Jan 1 1970 when the modem was initialized, like so many other TP link models. Also the 8th digit of the PIN is a checksum, so it's really just 7 digits to generate the complete rainbow table.
SSID is TP-LINK_HHHHHH

@PROger4everPublic: I've simplified a lot of the code, as the decompilation always adds a bunch of fluff. So it's not a 1 to 1 translation of the source. But the math checks out!
 

Attachments

  • tl_wr1042nd_16_wifi.zip
    664 bytes · Views: 45

PROger4everPublic

Active member
Feedback: 0 / 0 / 0
Joined
Feb 9, 2020
Messages
59
Reaction score
82
Credits
447
Yep, indeed a very similar (but much easier) calculation from the PIN. Looks like the PIN is based on the number of seconds since Jan 1 1970 when the modem was initialized, like so many other TP link models. Also the 8th digit of the PIN is a checksum, so it's really just 7 digits to generate the complete rainbow table.
SSID is TP-LINK_HHHHHH
I don't have enough Wi-Fi Keys to research the PIN statistics... Only the sticker.

@hydddra, maybe you have some appropriate real password and/or handshakes? Could you send them to me? It would be great to optimize the PIN order :)
 

hydddra

Member
Feedback: 0 / 0 / 0
Joined
Dec 30, 2019
Messages
19
Reaction score
8
Credits
39
I don't have enough Wi-Fi Keys to research the PIN statistics... Only the sticker.

@hydddra, maybe you have some appropriate real password and/or handshakes? Could you send them to me? It would be great to optimize the PIN order :)
Unfortunately, I don't have any handshakes from such networks.But if I understand correctly, your script can accept a pincode file as input and convert them into passwords and write them into a dictionary?
Here is a dictionary consisting of only pin codes.
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
I don't have enough Wi-Fi Keys to research the PIN statistics... Only the sticker.
Perhaps just brute force the PIN. It's possible this WIFI keygen is used for other TP-link models. Might not even be based on the PIN but directly based on the number of seconds since 1970 for units that don't do WPS....
 

PROger4everPublic

Active member
Feedback: 0 / 0 / 0
Joined
Feb 9, 2020
Messages
59
Reaction score
82
Credits
447
@PROger4everPublic: I've simplified a lot of the code, as the decompilation always adds a bunch of fluff. So it's not a 1 to 1 translation of the source. But the math checks out!
My previous post with implementation on C/C++ was deleted due to rules violation... Here's the rewritten and refactored version

The core features of the keygen:
1) Generates Wi-Fi Key by WPS PIN;
2) Accepts a single WPS PIN, a range of them or a file with them (requires renaming of the main function and recompilation);
3) Iterates over a range of WPS PINs correctly (iterates over 7-digit numbers and (re)calculates checksum in the last digit);
4) In file mode doesn't recalculate the checksum digit, so the full range of 8-digit numbers can be an input;

Usage examples:
Bash:
# Single WPS PIN mode:
$ ./tl_wr1042.keygen.wifi.bin 39620194
pin: 39620194, wifi_key: UkX3j4NT

# WPS PIN range mode. The last digit is being recalculated as WPS PIN checksum:
$ ./tl_wr1042.keygen.wifi.bin 39620195 39620207
pin: 39620194, wifi_key: UkX3j4NT
pin: 39620200, wifi_key: UmN9Bcud

# File mode. Requires renaming of the main function and recompilation:
$ nano tl_wr1042.keygen.wifi.cpp &&
  g++ tl_wr1042.keygen.wifi.cpp -o tl_wr1042.keygen.wifi.bin &&
  ./tl_wr1042.keygen.wifi.bin file.txt
pin: 39620194, wifi_key: UkX3j4NT
 

Attachments

  • tl_wr1042.keygen.wifi.zip
    1.2 KB · Views: 57

PROger4everPublic

Active member
Feedback: 0 / 0 / 0
Joined
Feb 9, 2020
Messages
59
Reaction score
82
Credits
447
Perhaps just brute force the PIN. It's possible this WIFI keygen is used for other TP-link models. Might not even be based on the PIN but directly based on the number of seconds since 1970 for units that don't do WPS....
I bruteforced the PIN as full range 8-digit numbers... Still got no matches against databases with popular wi-fi passwords...
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
I bruteforced the PIN as full range 8-digit numbers... Still got no matches against databases with popular wi-fi passwords...
Yeah I know how that feels. Some algorithms just aren't used in the real world. But then you get an Iskratel or a centurylink keygen that hits 1000s of caps.
But fabulous job on the C++ implementation!
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
Having never even gotten a hint about how ZTE wifi password are generated, I come across this file grepping for klmnp. The firmware name is non-ascii so I'm having a hard time tracking down the model. Hence, I'm not sure where it came from other then via @hydddra. As far as I can tell during a 10 sec glimpse this looks to contain an admin password generator. It was in the same location as /bin/zte_topsw_goahead which looks to contain the same algo. This might be as close as we'll ever come to a ZTE password generator.
So I thought I'd share for interested parties. Step 1: reverse this algo, then step 2: explore variations to see if anything hits against a ZTE WIFI password.
 

Attachments

  • zte_production_server_at.zip
    457.5 KB · Views: 28

fire-dance

Member
Feedback: 0 / 0 / 0
Joined
Apr 23, 2020
Messages
12
Reaction score
6
Credits
100
Yep, indeed a very similar (but much easier) calculation from the PIN. Looks like the PIN is based on the number of seconds since Jan 1 1970 when the modem was initialized, like so many other TP link models. Also the 8th digit of the PIN is a checksum, so it's really just 7 digits to generate the complete rainbow table.
SSID is TP-LINK_HHHHHH

@PROger4everPublic: I've simplified a lot of the code, as the decompilation always adds a bunch of fluff. So it's not a 1 to 1 translation of the source. But the math checks out!
I spent 2 days searching for the correct formula but I still haven't achieved it, I confirm that your topic is correct, the code is very complex here it is scattered referring to a bunch of code further, it is very difficult to find anything, have you tried QEMU? you need to do a dynamic analysis
 

fire-dance

Member
Feedback: 0 / 0 / 0
Joined
Apr 23, 2020
Messages
12
Reaction score
6
Credits
100
arrays are involved in the password generation process
1.auStack_88
Stores the PIN string ("39620194").
Can also be used to generate auStack_70 (charset)
2.auStack_78 and aiStack_a8
Stores the PIN digits ([3, 9, 6, 2, 0, 1, 9, 4]).
3. auStack_70
Stores the charset (character array of length 48).
Dynamic generated using the PIN (probably via auStack_88 or aiStack_a8).
4.auStack_38
Stores the final password (Ujma8gwm).
 

fire-dance

Member
Feedback: 0 / 0 / 0
Joined
Apr 23, 2020
Messages
12
Reaction score
6
Credits
100
Everything I wrote is wrong, I apologize:
To get the password Ujma8gwm, the charset should be:

charset[24] = 'U'
charset[2] = 'j'
charset[19] = 'm'
charset[1] = 'a'
charset[14] = '8'
charset[33] = 'g'
charset[42] = 'w'
charset[15] = 'm'
and also:
auStack_70:
Stores the charset, but is not dynamically generated in the current code. Copied from 0x3d38
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
@fire-dance, I really struggle with QEMU (as well as qiling) some times I get it to work, but as I'm not a programmer, cross-compiling is magic to me. It is usually faster (for me at least) to just look at the decompiliation in Ghidra and IDA and just try to match what I'm seeing in matlab. Then play around with the matlab code until it matches what it shown on the sticker.
That said, I am convinced my math is correct for the TP-link due to the similarities between the WIFI password algo and the admin password algo (not released due to forum rules)

Because there is no PCAP found with this algo, just means not enough of this units were sold in Slovania near people that capture WIFI traffic and share those online.
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149

PROger4everPublic

Active member
Feedback: 0 / 0 / 0
Joined
Feb 9, 2020
Messages
59
Reaction score
82
Credits
447

Attachments

  • zte_production_server_at.zip
    444.7 KB · Views: 10
  • zte_topsw_goahead.zip
    945.2 KB · Views: 15

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
Here's my stab at the reverse, it doesn't work, so doesn't break any rules HAHAHA
It's either taking the MAC or the IMEI as the input, depending on the password type requested.
The type also defines the order of the parts in the charset, upper first, or numbers first etc.
It can also pull the charset from NVRAM in a new twist. So if the default characters are for example in that region of the world not good, in can specify it's own.
Note the depressing sounding salts. Although that's probably lost in translation. "It'll be better tomorrow...." (It's not good today)
Upstream of the algo there is an example seed of 6 numbers separated by colons (1:81:11:11:21:21). Could be the mac, no idea if it is upper or lower case hex, or a decimal representation.

Lastly I'll attach a picture that includes the MAC as well as the IMEI if you want to experiment with the format of the MAC.



Code:
function pwd=zte_mf293n(mac);

numbers='2345678';
uppers='ABCDEFGHJKLMNPQRSTUVWXYZ';
lowers='abcdefghjkmnprstuvwxyz';
symbols='!@#%^()-_=+./?{}~';

salt1='ZTE''s future';
salt2='will be better!';

for n=1:6,
    mac_bytes{n}=upper(mac(n*2-1:n*2));
end

mac_string=mac_bytes{1};
for n=2:6,
    mac_string=[mac_string ':' mac_bytes{n}];
end

imei='863397051153050';
input_string1=[mac salt1];
input_string2=[mac salt2];

digest1=hasher(input_string1,'MD5');
digest2=hasher(input_string2,'MD5');

digest_sum=sum([digest1 digest2]);

charset=[numbers uppers lowers]; %which order?????
cs_len=length(charset);

pwd='';
for n=1:16,
    pwd(n)=charset(1+mod(double(digest1(n))+digest_sum,cs_len));
end
zte_mf293n.jpg
 

RealEnder

Active member
Feedback: 0 / 0 / 0
Joined
Dec 30, 2019
Messages
31
Reaction score
57
Credits
228
Last days did some runs with RT-GM3 generator against hashes in wpa-sec. Here are confirmed passwords and corresponding SNs:
3001017518 J8f4b5dheb
3014001750 A4dg2g6b86
3018003618 J8gk7kgkig
3018012559 Kej4b5j52j
3026023617 A7fj82fkig
3026023680 A7fj82fkig
3026050372 D8df6jdage
3026058620 Ak8aa4h3ji
3026060720 Ak9b4iaheb
3026060747 Aaake7j63k
3026063566 Hbi3g92853
3028000669 Kf24a4a52j
3028011076 Hdeh4idage
3028011814 F4eh4idage
3028038526 H7e4e72853
3050010177 Aegi5a5fb9
3104003963 E8a4a4fahf
3109008778 Jf3eje9eb9
3112000700 Aa79g9i3ka
3112010258 Jdgi5a7da8
3112011366 Hbga6j8eb9
3112043193 Ebea93bhfd
3112045775 Gbj7ibj53k
3112051839 Kbk4g9i3ka
3112054528 J9g2e7gkah
3112055730 A2ai93bhfd
3112058638 Jai8je2753
3112066431 B38h93bhfd
3112069583 Eah8kf3864
3112073875 Gbk6je2753
3112078541 B4akf8h2ji
3112086940 A3e2haa42j
3112090009 K89b7k9fda
3112099114 F46ie7gkah
3115003278 Jfi393fjig
3115005056 Haba5aageb
3115009041 B45h3h8eb9
3127004603 E29g2g9geb
3127007973 E9j9g93975
3127009742 D5e5b5a53k
3127012427 A8ei5adahf
3127012490 A8ei5adahf
3127013658 Jdj5d6j642
3127018795 Ge2dje7eb9
3131015568 Jej7f8g3ka
3131017878 Jf4ekf2975
3131021231 B369iba642
3131032889 Kh6ajek864
3131038434 F6b2b5djig
3131039198 Jhaajek864
3131040207 A69b2g3a86
3131040270 A69b2g3a86
3131048169 Kfh7iba642
3131049510 Aj6i829hfd
3131052224 F58d4i5da8
3131063057 Abdia4bahf
3131071000 Aaj3hai53k
3131071847 Aaj3hai53k
3131075718 J8h4iba642
3131852001 Bjk5ha6eb9
3131893627 A8gkha6eb9
3131893690 A8gkha6eb9
3134005575 Gbi5b5g3ka
3138004223 E47eje8geb
3138004350 A48fkf9hfd
3139006116 H68h3hdjig
3139011385 Gdhj7kh42j
3139022545 G8fa7kh42j
3139034154 F8ah6jg3ka
3139034526 H7ej93a642
3139037341 B48i7kh42j
3139039866 Hbkd2gbahf
3139048522 D39ja4j753
3139052001 Bjk5ha6eb9
3139059435 G7d4g95da8
3139060432 D49b4iekah
3139064353 E7bia4j753
3139093627 A8gkha6eb9
3139093690 A8gkha6eb9
3195886940 A3e2haa42j
3234001478 Jfj393ekji
3234004207 A69g2g6eda
3234004270 A69g2g6eda
3234019527 A8f6e7i542
3234019590 A8f6e7i542
3234038882 D9a9ad3a97
3234039098 Jhi9ad3a97
3234055095 Gef2e7i542
3234057426 H7d2e7i542
3234058001 Bjkb3h7feb
3237016103 E24dje7feb
3237036241 B47g5adjah
3237049751 B5e5g93a97
3239005907 A6h4a4j764
3239005970 A6h4a4j764
3239013091 B9ag3hdjah
3239035294 Fdg3d62986
3242001310 Aj47e7g43k
3242046152 D68h7k9ihf
3242048663 E8g6haa764
3242049530 A28ja4dkji
3242059129 Kad4g9i653
3253017500 Aa5f2g5feb
3253030183 Eadf4i7hge
3253048027 A89ja4e32j
3253048090 A89ja4e32j
3253048192 Dad3e7h653
3253052725 G6faa4e32j
3253052878 Jf48je3db9
3308004913 E3ej6jfaah
3308019142 D57a6jfaah
3308035153 E79h6jfaah
3308053856 Haj5ha5997
3308053892 Haj5ha5997
3308091142 D57a6jfaah
3309047018 D89a93a33k
3309047072 D89a93a33k
3309061965 Gak4ha6aa8
3309076655 G9h5ad8dda
3309076691 G9h5ad8dda
3313016509 E8f3a4eaah
3313016563 E8f3a4eaah
3313033884 Fbk6g9a442
3381047018 D89a93a33k
3381047072 D89a93a33k
Several observations:
  1. Some passwords are duplicated - this is expected because of the algo used.
  2. First two bytes are likly year of production, staring from 2020.
  3. First 5 bytes can be taken as constants and brute the second 5 bytes. This will leave us with only 2.5M candidates to try.
Attaching the generator, based on python script. To build the dict you can use it like this:
Code:
python rt_gm3_gen11.py | cut -f2 | sort -u > rt_gm3.dict
This is only valid for RT-GPON-HHHH and RT-5GPON-HHHH ESSIDs, which can also use other hardware/default algorithms.
 

Attachments

  • rt_gm3_gen11.zip
    815 bytes · Views: 37

RealEnder

Active member
Feedback: 0 / 0 / 0
Joined
Dec 30, 2019
Messages
31
Reaction score
57
Credits
228
BTW, just got a hit with this sn:
Code:
3112102717       A7gj6k9fda
3112102780       A7gj6k9fda
This means we can have 1 at 5th place, which will double the candidates in best case scenario, as we still start with 3112. We'll have to do extensive bruteforce to confirm the full keyspace.
 

drsnooker

Active member
Contributor
VIP Member
Feedback: 0 / 0 / 0
Joined
Aug 1, 2020
Messages
563
Reaction score
881
Credits
5,149
@RealEnder as always you take it to the next level!

I'm still a bit mystified about the ZTE algo. Seems like the zte_topsw_goahead has tons of security holes.
I'd be surprised if Grichter did not actually reverse the password generator. But looks like he didn't share it with the world.
Upto us now!
 
Top