You expect me to remember that? Part 1

Introduction:

It never surprises me the lengths some people will go to be lazy. Lately I’ve been doing password audits of networks with surprisingly decent password policies. Such as requiring a minimum length of 15 characters, and at least 2 of each upper, lower, special, and digits. Surely with such a stringent policy you wouldn’t expect to be able to crack any of the passwords. This however wasn’t the case thanks to two techniques that users have to promote their laziness, keyboard walking, and password doubling. In this two part article I’ll be covering how to attack those password and what methods can be used to prevent it..

Method: Keyboard walking

In part 1 I’ll be covering keyboard walking, this is the act of creating a password that is composed of a string of characters that move in a row or pattern on the keyboard. Common examples might be 1qaz, !@#$, ZAQ!, and 1234, I call these short strings “character sets”. It’s not certain if users think they are being smart, or they are just being lazy the fact remains that most patterns are pretty simple and are composed of only 3 or 4 characters. Using the four character sets above, and depending on the password policy a user may come up with something like ‘1qaz1234ZAQ!!@#$‘. This password meets all the complexity requirements, it’s greater than 15 characters, and has two of each character type. The problem is that if we knew the user used those 4 character sets we would only have to try at most 4^4(256) combintations to find the password (actually only 110 combinations contain an upper, lower, special, and digit).  In my testing I have found about 229 common length 4 character sets, if we wanted to build every combination of length 16 characters it would be 229^4 = 2,750,058,481 combinations. Given a standard desktop CPU could do 10M guesses a second it would take less than 5 minutes to compute every possible combination.

I see keyboard walking as being most prevalent in Active directory domains. In order to audit these the first step is to extract the hashes from the SAM database on the domain controller. I use a tool called fgdump, the output from this tool is saved as a pwdump file and it contains User name, User ID, LM hash, and NTLM hash, in a colon delimited format. Hopefully you will see “NO PASSWORD” in the LM field otherwise don’t bother with the NTLM as the LM’s can easily be cracked using rainbow tables. Depending what cracking tool your using you may have to extract the NTLM hashes from the pwdump file. Hashcat tools accept hashes only, so to extract the NTLM hashes do:

root@erebus:~# grep -v -h \$ 127.0.0.1.pwdump | sort -u | cut -d: -f4 > ntlm.hash

The command greps the file 127.0.0.1.pwdump for all hashes not containing $ (which are machine accounts), pipes it to sort using the unique switch, it is then piped to cut using a colon as a delimiter and selecting the 4th field, outputting to the file ntlm.hash. Conveniently JTR will accept the pwdump format directly. I will be using JTR to attack most of the keyboard walking accounts because JTR supports wordlist on stdin. I built a custom perl script that will allow you to pass keyboard combinations directly to JTR’s stdin, the script can be downloaded here. Here is an example of its usage:

root@erebus:~# perl keywalk-gen.pl 4 4
-pl,-pl,-pl,-pl,
-pl,-pl,-pl,-pL<
-pl,-pl,-pl,!@#$
-pl,-pl,-pl,!@34
-pl,-pl,-pl,!Q@W
..... <CTRL>+c to stop

The script will output every combination (1,387,488,001) of keyboard walks within the character set selected. In the example above character set 4 was selected, with a multiple of 4. This combination would give you 16 character password guesses. If the password policy you were auditing only required 12 character passwords you may try keywalk-gen.pl 4 3. You could also use the keywalk-gen script to build a dictionary by redirecting output into a file, but why waste hard drive space on a dictionary when words can be built on the fly and piped to stdin. Here is an example of the syntax used for JTR:
root@erebus:~# perl keywalk-gen.pl 4 4 | john.exe --stdin --format=nt 127.0.0.1.pwdump
Loaded 1264 password hashes with no different salts (NT MD4 [128/128 SSE2 + 32/32])
Remaining 1003 password hashes with no different salts
1qaz1qaz!QAZ!QAZ (user476)
1qaz1qaz@WSX@WSX (user808)
1qaz!QAZmko0MKO) (user1167)
1qazZAQ!2wsxXSW@ (user508)
1qaz2wsx@WSX1qaz (user950)

From the example above 1264 NT MD4(NTLM) hashes were loaded.  Using my laptop it took 22 minutes to generate all 1.38 billion combinations. This technique could also be applied to any algorithm that JTR supports. In addition this could be used to pipe plains into oclHashcat-plus and apply rules to the keywalk patterns, or attack harder algorithms such as md5(crypt). Just remember that oclHashcat-plus only supports up to 15 characters plains as an input so keywalk-gen.pl 4 4 would be to large. Run keywalk-gen.pl without any arguments to see all of the characters sets available to choose from. Protip: Use the gate tool from Hashcat-utilites, splitting the wordlist among mutliple cores or computers as was discribed in “Multicore dictionary support in JTR using Hashcat utilities.”

Conclusion:

Hopefully it’s easy to see how vulnerable those keyboard walk passwords are. Next I’ll be covering how to attack doubled passwords and what steps we can use to help prevent it.

Links: keywalk-gen.pl

Comments (1)

  1. 3:53 am, August 12, 2011Bugtrace  / Reply

    oops, my jtr(ver: 1.7.8-jumbo-5 [linux-x86-64]) occurs error:
    # perl keywalk-gen.pl 3 3 | ./jtr/john --stdin --format=raw-md5 ~pentest/2011.txt --nolog
    Using raw-md5 mode, by linking to md5_gen(0) functions
    Loaded 608711 password hashes with no different salts (Raw MD5 [gen])
    Remaining 608622 password hashes with no different salts
    #EDC@WSX1qaz (?)
    Segmentation fault

Leave a Reply

Allowed Tags - You may use these HTML tags and attributes in your comment.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">