1

So I am on an engagement and grabbed some hashes but cracking them has come to no avail. I believe I know the hash type (PBKDF2-HMAC-SHA256) but I am not sure what round size they used. This got me thinking doesn't this make it impossible to crack or am I missing something. Because even if say you knew the plain text password and salt (obviously a very contrived scenario) you'd still need to try every round size until you found the one they used.

Is this thinking correct or am I missing something?

EDIT: This is important info looking back and I apologize for the confusions about the rounds being missing. The application returns hashes in two different parts of a JSON object. {...,"Password":"(Base64encoded(27 characters))","PasswordSalt":"(Base64encoded(24 characters))",...}. Which is why the hashes do not include a rounds identifier.

So PBKDF2-HMAC-SHA256 came from how they store passwords in a different part of the application and it was all I could find through OSINT. Looking at the password lengths and playing around with Python passlib it seems the passwords are stored as pbkdf2_sha1. I can make sure I'm right but looping through all the rounds and seeing if any come out to the password that I have. It will still take a while since, as the community has said, 100,000 rounds isn't unheard of and sadly they aren't using the default of 29,000.

EDIT EDIT: Just ran my known password against its hash through all rounds 1-100,000 and didn't get a hit. Seems my intuition about it being Sha1 were wrong. Trying SHA-256 now with the same approach.

EDIT EDIT: Well my hope is quickly depleting. I've tried SHA_1,256,and 512 all from 1 to 100,000 rounds and none of them match my hash. The hash lengths and values seem to match perfectly with the description but experiments are seeming to prove different.

I know this isn't really a programming forum but for completeness here is the code I was using to check my hash against all the generated ones.

import concurrent.futures
global quit
from passlib.hash import pbkdf2_sha512
quit = False

def hasher(round, quit):
    if(not quit):
        hash = pbkdf2_sha512.using(salt=(passlib.utils.binary.ab64_decode('xpN14Zl95QQNOKffgsERSw==')), rounds=round).hash('Password').split('$')[-1]
    if(hash[0:5] == '278Vu'):
        print(round) #found it
        quit = True
    if(round % 5000 == 0):
        print(round) #status update


exec = concurrent.futures.ThreadPoolExecutor(max_workers=4)
print("Execing")
for i in range(1,100001):
    exec.submit(hasher,i, quit)

EDIT EDIT EDIT: Seems the hash identifier tool here https://github.com/psypanda/hashID has labeled them as Peoplesoft passwords. I am not sure if this is a false positive because the application doesn't seem to use peoplesoft anywhere. Also It seems Peoplesoft hashes are not salted and mine returns a salt. There is one post on the matter here, https://hashcat.net/forum/thread-6639.html but it is vague. Any help in this regard?

  • If you knew the password/salt, not knowing the exact number of iterations is not a very big barrier. – forest Jun 9 '18 at 7:23
  • well PBKDF2 is a very slow hash function (by design) and 20000 iterations is a lot so I wouldn't say its trivial. Even if you do some guessing and say they wouldn't put it below 10000 for robustness that's still 10,000 tries. – staticFlow Jun 9 '18 at 7:33
  • The idea of PBKDF2 is, that even knowing all parameters you will still need huge time for brute force. Actually you question partially confirms that PBKDF2 is not bad :) – mentallurg Jun 9 '18 at 11:49
  • 1
    How confident are you that that is the hash type? No well-known application omits rounds in this way (that I'm aware of). Did the number of rounds accidentally get truncated during collection of the hash? Otherwise, it would be pretty unusual for a developer do this. It would have to be a local/custom application - and a very naive one at that. – Royce Williams Jun 9 '18 at 14:50
  • It's possible they use a pepper, in which case you're probably out of luck. – AndrolGenhald Jun 12 '18 at 13:25
1

This would usually only be a mild, temporary barrier to cracking.

Leaving off the number of rounds would be a thin layer of obscurity. The only way such a hash could even work would be if the software had a hard-coded or algorithmic way to determine the number of rounds. So that software could simply be reverse-engineered to discover the number of rounds.

It would also be quite unusual. Most hash formats that use rounds include the number of rounds as part of the hash itself (the "1000" in this example, taken from the list of hashcat example hashes):

sha256:1000:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt

This means that the easiest workaround is to simply generate a version of the hash with many numbers of rounds:

sha256:1:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt
sha256:2:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt
sha256:3:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt
sha256:4:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt
sha256:5:MTc3MTA0MTQwMjQxNzY=:PYjCU215Mi57AYPKva9j7mvF4Rc5bCnt

... and then feed all of them to your cracking software. (Because the number of rounds in this hash format is designed to be variable, cracking software should be able to handle this just fine.)

That being said, there's usually a practical upper limit to the number of rounds - beyond which it would take too long for interactive users to tolerate waiting for their password to be verified. 100,000 rounds would be pretty unusual, but not impossible. But if this is some custom, bespoke application, an unusually high number of rounds might be tolerable. So if it's some bespoke application, trying to "hide" the number of rounds might make it a little harder for the attacker. And since PBKDF2 is a pretty slow hash, if we assume that the defender picked a pretty high number of rounds, this approach might actually make things harder.

So if an attack on rounds from 1 to 50,000, using common wordlists and attacks, didn't yield any results in a day or two ... I'd be inclined to start to think that it might be different hash type - and would probably also trying to grab the software/firmware that generates/verifies the hashes and reverse engineering it. Actually, I'd probably do that anyway why I was waiting for the cracking job to finish. :)

  • 100,000 iterations is not at all unusual. – forest Jun 10 '18 at 2:21
  • Given how long it was the maximum for LastPass (which at least used to default to 5000 rounds, not sure if that's still true) ... I would dispute that. – Royce Williams Jun 10 '18 at 4:13
  • Perhaps. I was thinking more of VeraCrypt, FileVault, and LUKS which regularly use more. – forest Jun 10 '18 at 4:15
  • That's fair - FDE users can tolerate a significant pause during authentication. On an 8-core AMD FX-8350, attacking a 100,000-round PBKDF2-HMAC-SHA256 using all possible optimizations and parallelization, hashcat can only make one crack attempt about every 20 seconds. I suspect that the other suites you describe are not as heavily optimized, such that a 100K auth attempt would take 30 seconds or more. That's a wild guess, though - and that's with OpenCL brokering the deal. :) I'll have to test this with LUKS! – Royce Williams Jun 10 '18 at 4:21
  • 1/20 H/s for 100k round PBKDF2-SHA256? That's only 5 kH/s of SHA-256. You must be doing something wrong since that's extremely low, even for regular hashcat and not oclhashcat. Anyway you're right wrt tolerating a different length of pause. 500,000 iterations of SHA-512 on my laptop takes about 3 seconds which would probably be irritating to someone who just wants to get their Netflix password, but not to someone who's gonna wait another 20 seconds for the system to boot. – forest Jun 10 '18 at 4:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.