Evengard / cntlm

PLEASE NOTE THAT THIS FORK IS NOT MAINTAINED! For the maintained fork please refer to https://github.com/versat/cntlm. Cntlm is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy intended to help you break free from the chains of Microsoft proprietary world. More info on http://cntlm.sourceforge.net/ website. THIS VERSION SUPPORTS SSPI, WHICH ALLOWS USERS WITH SMARTCARD AUTHENTICATION TO USE IT ON WINDOWS BOXES!
GNU General Public License v2.0
129 stars 46 forks source link

How does cntlm calculate hashes? Is it possible to use NTLM hash to calculate PassNTLMv2? #8

Open Cnoob opened 8 years ago

Cnoob commented 8 years ago

Hello!

I'm working in the environment with smartcard logon and ntlmv2/Kerberos enforced. Cntlm with NTLMSSPI is not an option (probally need NTLMv2 SSPI which is not implemented at this moment) so I'm trying to "bypass" a corporate proxy with cntlm and NTLM hash of the password which I eventually know :)

I've noticed that cntlm -H results are different from the "standard" password hashes. As far as I understand, NTLM hash is an MD4(unicode(Password)). For example, NTLM hash of "password" is 8846F7EAEE8FB117AD06BDD830B7586C. However, cntlm -H returns PassNT 77B9081511704EE852F94227CF48A793 for the same "password".

PassNTLMv2 value that is produced by cntlm -H is also different from "standard" HMACMD5(NTLMhash, uppercase username + domain).

I've found an appropriate portions of code in ntlm.c but unfortunately can not understand why hash functions are working this way.

char *ntlm_hash_nt_password(char *password) { char *u16, *keys; int len;

keys = new(21 + 1);
len = unicode(&u16, password);
md4_buffer(u16, len, keys);

memset(keys+16, 0, 5);
memset(u16, 0, len);
free(u16);

return keys;

}

char *ntlm2_hash_password(char *username, char *domain, char *password) { char *tmp, *buf, *passnt, *passnt2; int len;

passnt = ntlm_hash_nt_password(password);

buf = new(strlen(username)+strlen(domain) + 1);
strcat(buf, username);
strcat(buf, domain);
uppercase(buf);
len = unicode(&tmp, buf);

passnt2 = new(16 + 1);
hmac_md5(passnt, 16, tmp, len, passnt2);

free(passnt);
free(tmp);
free(buf);

return passnt2;

}`

The main question is:

Is it possible to implement "pass-the-hash"-like functionality in cntlm (calculate PassNTLMv2 from username, domain and NTLM password hash)?

me0wday commented 8 years ago

Have you had any luck with this? I am also interested in NTLMv2 version of this

Evengard commented 7 years ago

Actually for me it seemed that the NTLM hash using SSPI was not exactly an NTLM hash at all, they just probably called it the same for backwards compability or stuff like that. Originally I created the SSPI version to pierce through my corporate firewall too, it was using Negotiate but worked with NTLM just fine too (Negotiate was actually used by the browser as the research showed). It really seems that when the system is going through the SSPI route it doesn't care about what is the "type" it uses.

Anyway, as I wrote in the commit messages, to allow other SSPI handles (called "security support providers" and which you can get through EnumerateSecurityPackages WinAPI function as per msdn) - I need to change the way how the header name is generated, because I just went a kind of "easy way", just patching inside the ntlm_request/ntlm_response functions. Which means NTLM is already predefined at this stage. As I didn't needed it, I just left it as is, but any pull requests would be welcome.