Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix LM hash computation #1626

Closed
wants to merge 1 commit into from
Closed

Conversation

laxa
Copy link
Contributor

@laxa laxa commented Oct 5, 2023

For some reason, when performing NTLM connection, impacket always compute the LM hash of the provided password. However, this operation fails when using special characters ('µ') for example:

$ PYTHONPATH=$PWD examples/smbclient.py 'test:Passwordµ@192.168.88.134' -debug
Impacket v0.12.0.dev1+20230928.173259.06217f05 - Copyright 2023 Fortra

[+] Impacket Library Installation Path: /home/laxa/Documents/impacket2/impacket
Traceback (most recent call last):
  File "/home/laxa/Documents/impacket2/examples/smbclient.py", line 102, in main
    smbClient.login(username, password, domain, lmhash, nthash)
  File "/home/laxa/Documents/impacket2/impacket/smbconnection.py", line 278, in login
    return self._SMBConnection.login(user, password, domain, lmhash, nthash)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/laxa/Documents/impacket2/impacket/smb3.py", line 1009, in login
    type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, respToken['ResponseToken'], user, password, domain, lmhash, nthash)
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/laxa/Documents/impacket2/impacket/ntlm.py", line 628, in getNTLMSSPType3
    ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge'])
                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/laxa/Documents/impacket2/impacket/ntlm.py", line 443, in __init__
    lmhash = compute_lmhash(password)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/laxa/Documents/impacket2/impacket/ntlm.py", line 746, in compute_lmhash
    lmhash += __DES_block(b(password[7:14]), KNOWN_DES_INPUT)
                          ^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/six.py", line 644, in b
    return s.encode("latin-1")
           ^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'latin-1' codec can't encode character '\u039c' in position 1: ordinal not in range(256)
[-] 'latin-1' codec can't encode character '\u039c' in position 1: ordinal not in range(256)

The documentation in the code states that it follows the RFC (https://datatracker.ietf.org/doc/rfc2433/). However, this RFC does not state how to handle special characters.
Google did not came up with anything related for handling these characters. However, I found an online LM hash calculator (https://tobtu.com/lmntlm.php) that calculated the same LM hash value that a Windows computer.
The JavaScript code of this website was converted for impacket.

@NeffIsBack
Copy link
Contributor

This also fixes issues with the symbol and therefore a ton of issues which came up over the years. Currently it is not possible to login with a password containing the . Would be nice if this could be merged soon. Thank y'all for all the work on impacket :)

Related issues:
byt3bl33d3r/CrackMapExec#786
Pennyw0rth/NetExec#129
and probably a few other but i can't find them at the moment

@anadrianmanrique
Copy link
Contributor

hello, I've been checking the current cumpute lm hash implementation

def compute_lmhash(password):
. It seems it's actually kind of honoring microsoft's doc https://learn.microsoft.com/en-us/windows-server/security/kerberos/passwords-technical-overview. According to the specs, password characters should be in the extended ansi (a.k.a latin-1 I think) encoding. The problem in the impacket's code is in
password = password.upper()
which uppercases the µ into the capital Μ. µ is actually a member of the latin-1 set, but not Μ ( capital µ ). On the other hand €, doesn't even belong to extended ANSI.
The code in this PR it's a workaround that makes impacket avoid crashing at the time of interpreting the password string. Bear in mind that LM hash is not even checked in the remote server, in most of the windows versions.
So, I would say that, for now, for those invalid characters in the context of LM hashing, compute the fixed value 385359f4ebcc247b57a2ab140e714cd1 which is the standard value for LM hashes in most of the scenarios.
The current algorithm should eventually (?) be tested against a target that enforces LM hash authentication though.

@anadrianmanrique
Copy link
Contributor

I'll create a PR with this fix

@anadrianmanrique
Copy link
Contributor

just created #1723 . If somebody could give it a go, it would be awesome

@NeffIsBack
Copy link
Contributor

just created #1723 . If somebody could give it a go, it would be awesome

Gonna try and test it later👍🏼

@NeffIsBack
Copy link
Contributor

Honestly i can't get LM authentication to work based on only the LM Hash (Screenshot based on #1626):
image
Although when applying the password with a special character and LM Hash enabled the DC stores the default LM hash anyway (Screenshot based on #1626):
image

So neither with #1626 nor with #1723 i can get LM auth to be working (besides the fact that the DC does not store the LM hash if special characters are used). As this is an extrem edge case and both PRs are preventing normal password authentication from crashing either way is fine imo.
The following is #1723:
image

@anadrianmanrique
Copy link
Contributor

@NeffIsBack interesting, from what I tested hashes for passwords with standard characters are correctly calculated in all versions. Differences appear when 'special characters' are processed. On the other hand looking at some implementations, they don't seem to be honoring the original specs https://doxygen.reactos.org/de/d62/dll_2win32_2advapi32_2wine_2crypt__lmhash_8c.html#a2801598865913a98bf3cfb0c2f5edf03 , https://github.com/dchest/historic-password-hashes/blob/master/winnt-owf.c , which makes all a bit more confusing.
The fact that you weren't able to login even with standard characters doesn't seem to be related to the PR changes, as hashes seems to be correct. We could try to follow this up in a separate issue..

@anadrianmanrique
Copy link
Contributor

closing this one in favor of #1723. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Unexpected problem or unintended behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants