From e8f2f7b30e04cbae9eaa566524e22ed7dfcb3d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Sat, 2 Jun 2012 18:21:04 -0400 Subject: [PATCH] winpr/tools/hash: added NTLM hashing tool --- client/test/CMakeLists.txt | 1 + include/winpr/ntlm.h | 46 +++++++++++ winpr/CMakeLists.txt | 2 + winpr/sspi/NTLM/ntlm_compute.c | 42 +--------- winpr/tools/CMakeLists.txt | 21 +++++ winpr/tools/hash/CMakeLists.txt | 24 ++++++ winpr/tools/hash/hash.c | 125 ++++++++++++++++++++++++++++++ winpr/tools/hash/winpr-hash | Bin 0 -> 8690 bytes winpr/utils/CMakeLists.txt | 4 + winpr/utils/ntlm.c | 131 ++++++++++++++++++++++++++++++++ 10 files changed, 358 insertions(+), 38 deletions(-) create mode 100644 include/winpr/ntlm.h create mode 100644 winpr/tools/CMakeLists.txt create mode 100644 winpr/tools/hash/CMakeLists.txt create mode 100644 winpr/tools/hash/hash.c create mode 100755 winpr/tools/hash/winpr-hash create mode 100644 winpr/utils/ntlm.c diff --git a/client/test/CMakeLists.txt b/client/test/CMakeLists.txt index 4a4f6fca7..f07f72dc3 100644 --- a/client/test/CMakeLists.txt +++ b/client/test/CMakeLists.txt @@ -24,3 +24,4 @@ target_link_libraries(freerdp-test freerdp-core) target_link_libraries(freerdp-test freerdp-gdi) target_link_libraries(freerdp-test freerdp-utils) target_link_libraries(freerdp-test freerdp-channels ${CMAKE_DL_LIBS}) + diff --git a/include/winpr/ntlm.h b/include/winpr/ntlm.h new file mode 100644 index 000000000..6e8759ceb --- /dev/null +++ b/include/winpr/ntlm.h @@ -0,0 +1,46 @@ +/** + * WinPR: Windows Portable Runtime + * NTLM Utils + * + * Copyright 2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WINPR_UTILS_NTLM_H +#define WINPR_UTILS_NTLM_H + +#include +#include +#include +#include +#include + +WINPR_API BYTE* NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash); +WINPR_API BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash); + +WINPR_API BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, + UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash); +WINPR_API BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, + UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash); + +#ifdef UNICODE +#define NTOWFv1 NTOWFv1W +#define NTOWFv2 NTOWFv2W +#else +#define NTOWFv1 NTOWFv1A +#define NTOWFv2 NTOWFv2W +#endif + +#endif /* WINPR_UTILS_NTLM_H */ + diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 77611e022..1b4e1b5f9 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -27,3 +27,5 @@ add_subdirectory(rpc) add_subdirectory(sspi) add_subdirectory(registry) +add_subdirectory(tools) + diff --git a/winpr/sspi/NTLM/ntlm_compute.c b/winpr/sspi/NTLM/ntlm_compute.c index dc4f27de2..e2ce6e385 100644 --- a/winpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/sspi/NTLM/ntlm_compute.c @@ -21,6 +21,7 @@ #include "../sspi.h" #include +#include #include #include "ntlm_compute.h" @@ -159,21 +160,6 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context) } } -void ntlm_compute_ntlm_hash(UINT16* password, UINT32 length, char* hash) -{ - /* NTLMv1("password") = 8846F7EAEE8FB117AD06BDD830B7586C */ - - MD4_CTX md4_ctx; - - /* Password needs to be in unicode */ - - /* Apply the MD4 digest algorithm on the password in unicode, the result is the NTLM hash */ - - MD4_Init(&md4_ctx); - MD4_Update(&md4_ctx, password, length); - MD4_Final((void*) hash, &md4_ctx); -} - static void ascii_hex_string_to_binary(char* str, unsigned char* hex) { int i; @@ -278,36 +264,16 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) { - char* p; - SecBuffer buffer; - char ntlm_hash[16]; - if (context->identity.PasswordLength > 0) { - /* First, compute the NTLMv1 hash of the password */ - ntlm_compute_ntlm_hash(context->identity.Password, context->identity.PasswordLength, ntlm_hash); - } - - sspi_SecBufferAlloc(&buffer, context->identity.UserLength + context->identity.DomainLength); - p = (char*) buffer.pvBuffer; - - /* Concatenate(Uppercase(username),domain)*/ - CopyMemory(p, context->identity.User, context->identity.UserLength); - CharUpperBuffW((LPWSTR) p, context->identity.UserLength / 2); - - CopyMemory(&p[context->identity.UserLength], context->identity.Domain, context->identity.DomainLength); - - if (context->identity.PasswordLength > 0) - { - /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */ - HMAC(EVP_md5(), (void*) ntlm_hash, 16, buffer.pvBuffer, buffer.cbBuffer, (void*) hash, NULL); + NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength, + (LPWSTR) context->identity.User, context->identity.UserLength, + (LPWSTR) context->identity.Domain, context->identity.DomainLength, (BYTE*) hash); } else { ntlm_fetch_ntlm_v2_hash(context, hash); } - - sspi_SecBufferFree(&buffer); } void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) diff --git a/winpr/tools/CMakeLists.txt b/winpr/tools/CMakeLists.txt new file mode 100644 index 000000000..8c782bcbc --- /dev/null +++ b/winpr/tools/CMakeLists.txt @@ -0,0 +1,21 @@ +# WinPR: Windows Portable Runtime +# winpr cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_subdirectory(hash) + diff --git a/winpr/tools/hash/CMakeLists.txt b/winpr/tools/hash/CMakeLists.txt new file mode 100644 index 000000000..b8a1fc46c --- /dev/null +++ b/winpr/tools/hash/CMakeLists.txt @@ -0,0 +1,24 @@ +# WinPR: Windows Portable Runtime +# winpr-hash cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_executable(winpr-hash + hash.c) + +target_link_libraries(winpr-hash winpr-utils) + diff --git a/winpr/tools/hash/hash.c b/winpr/tools/hash/hash.c new file mode 100644 index 000000000..ebe8f5952 --- /dev/null +++ b/winpr/tools/hash/hash.c @@ -0,0 +1,125 @@ +/** + * WinPR: Windows Portable Runtime + * NTLM Hashing Tool + * + * Copyright 2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +/** + * Define NTOWFv1(Password, User, Domain) as + * MD4(UNICODE(Password)) + * EndDefine + * + * Define LMOWFv1(Password, User, Domain) as + * ConcatenationOf(DES(UpperCase(Password)[0..6], "KGS!@#$%"), + * DES(UpperCase(Password)[7..13], "KGS!@#$%")) + * EndDefine + * + * Define NTOWFv2(Password, User, Domain) as + * HMAC_MD5(MD4(UNICODE(Password)), + * UNICODE(ConcatenationOf(UpperCase(User), Domain))) + * EndDefine + * + * Define LMOWFv2(Password, User, Domain) as + * NTOWFv2(Password, User, Domain) + * EndDefine + * + */ + +int main(int argc, char* argv[]) +{ + int index = 1; + BYTE NtHash[16]; + char* User = NULL; + UINT32 UserLength; + char* Domain = NULL; + UINT32 DomainLength; + char* Password = NULL; + UINT32 PasswordLength; + + while (index < argc) + { + if (strcmp("-d", argv[index]) == 0) + { + index++; + + if (index == argc) + { + printf("missing domain\n"); + exit(1); + } + + Domain = argv[index]; + } + else if (strcmp("-u", argv[index]) == 0) + { + index++; + + if (index == argc) + { + printf("missing username\n"); + exit(1); + } + + User = argv[index]; + } + else if (strcmp("-p", argv[index]) == 0) + { + index++; + + if (index == argc) + { + printf("missing password\n"); + exit(1); + } + + Password = argv[index]; + } + else if (strcmp("-h", argv[index]) == 0) + { + printf("winpr-hash: NTLM hashing tool\n"); + printf("Usage: winpr-hash -u -p [-d ]\n"); + exit(1); + } + + index++; + } + + if ((!User) || (!Password)) + { + printf("missing username or password\n"); + exit(1); + } + + UserLength = strlen(User); + PasswordLength = strlen(Password); + DomainLength = (Domain) ? strlen(Domain) : 0; + + NTOWFv2A(Password, PasswordLength, User, UserLength, Domain, DomainLength, NtHash); + + for (index = 0; index < 16; index++) + printf("%02x", NtHash[index]); + + printf("\n"); + + return 0; +} + diff --git a/winpr/tools/hash/winpr-hash b/winpr/tools/hash/winpr-hash new file mode 100755 index 0000000000000000000000000000000000000000..7ee8850c2d9b93b017e89470472af1876e64f027 GIT binary patch literal 8690 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 literal 0 HcmV?d00001 diff --git a/winpr/utils/CMakeLists.txt b/winpr/utils/CMakeLists.txt index 33b1c427c..7363a123e 100644 --- a/winpr/utils/CMakeLists.txt +++ b/winpr/utils/CMakeLists.txt @@ -18,6 +18,7 @@ # limitations under the License. set(WINPR_UTILS_SRCS + ntlm.c print.c stream.c) @@ -29,5 +30,8 @@ if (NOT WIN32) target_link_libraries(winpr-utils winpr-crt) endif() +target_link_libraries(winpr-utils ${ZLIB_LIBRARIES}) +target_link_libraries(winpr-utils ${OPENSSL_LIBRARIES}) + install(TARGETS winpr-utils DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/winpr/utils/ntlm.c b/winpr/utils/ntlm.c new file mode 100644 index 000000000..be2851705 --- /dev/null +++ b/winpr/utils/ntlm.c @@ -0,0 +1,131 @@ +/** + * WinPR: Windows Portable Runtime + * NTLM Utils + * + * Copyright 2012 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Define NTOWFv1(Password, User, Domain) as + * MD4(UNICODE(Password)) + * EndDefine + */ + +BYTE* NTOWFv1W(LPWSTR Password, UINT32 PasswordLength, BYTE* NtHash) +{ + MD4_CTX md4_ctx; + + if (!Password) + return NULL; + + if (!NtHash) + NtHash = malloc(16); + + MD4_Init(&md4_ctx); + MD4_Update(&md4_ctx, Password, PasswordLength); + MD4_Final((void*) NtHash, &md4_ctx); + + return NtHash; +} + +BYTE* NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash) +{ + LPWSTR PasswordW = NULL; + + PasswordW = (LPWSTR) malloc(PasswordLength * 2); + MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength); + + NtHash = NTOWFv1W(PasswordW, PasswordLength, NtHash); + + free(PasswordW); + + return NtHash; +} + +/** + * Define NTOWFv2(Password, User, Domain) as + * HMAC_MD5(MD4(UNICODE(Password)), + * UNICODE(ConcatenationOf(UpperCase(User), Domain))) + * EndDefine + */ + +BYTE* NTOWFv2W(LPWSTR Password, UINT32 PasswordLength, LPWSTR User, + UINT32 UserLength, LPWSTR Domain, UINT32 DomainLength, BYTE* NtHash) +{ + BYTE* buffer; + BYTE NtHashV1[16]; + + if ((!User) || (!Password)) + return NULL; + + if (!NtHash) + NtHash = (BYTE*) malloc(16); + + NTOWFv1W(Password, PasswordLength, NtHashV1); + + buffer = (BYTE*) malloc(UserLength + DomainLength); + + /* Concatenate(UpperCase(User), Domain) */ + + CopyMemory(buffer, User, UserLength); + CharUpperBuffW((LPWSTR) buffer, UserLength / 2); + CopyMemory(&buffer[UserLength], Domain, DomainLength); + + /* Compute the HMAC-MD5 hash of the above value using the NTLMv1 hash as the key, the result is the NTLMv2 hash */ + HMAC(EVP_md5(), (void*) NtHashV1, 16, buffer, UserLength + DomainLength, (void*) NtHash, NULL); + + free(buffer); + + return NtHash; +} + +BYTE* NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, + UINT32 UserLength, LPSTR Domain, UINT32 DomainLength, BYTE* NtHash) +{ + LPWSTR UserW = NULL; + LPWSTR DomainW = NULL; + LPWSTR PasswordW = NULL; + + UserW = (LPWSTR) malloc(UserLength * 2); + DomainW = (LPWSTR) malloc(DomainLength * 2); + PasswordW = (LPWSTR) malloc(PasswordLength * 2); + + MultiByteToWideChar(CP_ACP, 0, User, UserLength, UserW, UserLength); + MultiByteToWideChar(CP_ACP, 0, Domain, DomainLength, DomainW, DomainLength); + MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength); + + NtHash = NTOWFv2W(PasswordW, PasswordLength * 2, UserW, UserLength * 2, DomainW, DomainLength * 2, NtHash); + + free(UserW); + free(DomainW); + free(PasswordW); + + return NtHash; +} +