From 6df916d751e72fc9a1febc07bb59c4ddd886c043 Mon Sep 17 00:00:00 2001 From: Steve Holme Date: Sun, 29 May 2016 22:57:40 +0200 Subject: [PATCH] loadlibrary: Only load system DLLs from the system directory Inspiration provided by: Daniel Stenberg and Ray Satiro Bug: https://curl.haxx.se/docs/adv_20160530.html Ref: Windows DLL hijacking with curl, CVE-2016-4802 --- lib/Makefile.inc | 4 +- lib/Makefile.vc6 | 3 +- lib/curl_sspi.c | 7 +- lib/system_win32.c | 130 +++++++++++++++++++++++++++++ lib/system_win32.h | 39 +++++++++ lib/telnet.c | 3 +- packages/Symbian/group/libcurl.mmp | 2 +- 7 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 lib/system_win32.c create mode 100644 lib/system_win32.h diff --git a/lib/Makefile.inc b/lib/Makefile.inc index b573e932e..0ed998c13 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -53,7 +53,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ - x509asn1.c http2.c smb.c curl_endian.c curl_des.c + x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ @@ -72,7 +72,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h + curl_printf.h system_win32.h LIB_RCFILES = libcurl.rc diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 index d6c815e47..b4cb229a6 100644 --- a/lib/Makefile.vc6 +++ b/lib/Makefile.vc6 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1999 - 2015, Daniel Stenberg, , et al. +# Copyright (C) 1999 - 2016, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -616,6 +616,7 @@ X_OBJS= \ $(DIROBJ)\speedcheck.obj \ $(DIROBJ)\splay.obj \ $(DIROBJ)\ssh.obj \ + $(DIROBJ)\system_win32.obj \ $(DIROBJ)\vauth.obj \ $(DIROBJ)\cleartext.obj \ $(DIROBJ)\cram.obj \ diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index 04eac489b..54bbef6f6 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -27,6 +27,7 @@ #include #include "curl_sspi.h" #include "curl_multibyte.h" +#include "system_win32.h" #include "warnless.h" /* The last #include files should be: */ @@ -117,9 +118,9 @@ CURLcode Curl_sspi_global_init(void) /* Load SSPI dll into the address space of the calling process */ if(securityDll) - s_hSecDll = LoadLibrary(TEXT("security.dll")); + s_hSecDll = Curl_load_library(TEXT("security.dll")); else - s_hSecDll = LoadLibrary(TEXT("secur32.dll")); + s_hSecDll = Curl_load_library(TEXT("secur32.dll")); if(!s_hSecDll) return CURLE_FAILED_INIT; diff --git a/lib/system_win32.c b/lib/system_win32.c new file mode 100644 index 000000000..73d30b421 --- /dev/null +++ b/lib/system_win32.c @@ -0,0 +1,130 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(WIN32) + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + +#include +#include "system_win32.h" + +/* The last #include files should be: */ +#include "curl_memory.h" +#include "memdebug.h" + +#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) +#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 +#endif + +#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32) +#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 +#endif + +/* We use our own typedef here since some headers might lack these */ +typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); + +/* See function definitions in winbase.h */ +#ifdef UNICODE +# ifdef _WIN32_WCE +# define LOADLIBARYEX L"LoadLibraryExW" +# else +# define LOADLIBARYEX "LoadLibraryExW" +# endif +#else +# define LOADLIBARYEX "LoadLibraryExA" +#endif + +/* + * Curl_load_library() + * + * This is used to dynamically load DLLs using the most secure method available + * for the version of Windows that we are running on. + * + * Parameters: + * + * filename [in] - The filename or full path of the DLL to load. If only the + * filename is passed then the DLL will be loaded from the + * Windows system directory. + * + * Returns the handle of the module on success; otherwise NULL. + */ +HMODULE Curl_load_library(LPCTSTR filename) +{ + HMODULE hModule = NULL; + LOADLIBRARYEX_FN pLoadLibraryEx = NULL; + + /* Get a handle to kernel32 so we can access it's functions at runtime */ + HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32")); + if(!hKernel32) + return NULL; + + /* Attempt to find LoadLibraryEx() which is only available on Windows 2000 + and above */ + pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX); + + /* Detect if there's already a path in the filename and load the library if + there is. Note: Both back slashes and forward slashes have been supported + since the earlier days of DOS at an API level although they are not + supported by command prompt */ + if(_tcspbrk(filename, TEXT("\\/"))) + hModule = pLoadLibraryEx ? + pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(filename); + /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only + supported on Windows Vista, Windows Server 2008, Windows 7 and Windows + Server 2008 R2 with this patch or natively on Windows 8 and above */ + else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) { + /* Load the DLL from the Windows system directory */ + hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + } + else { + /* Attempt to get the Windows system path */ + UINT systemdirlen = GetSystemDirectory(NULL, 0); + if(systemdirlen) { + /* Allocate space for the full DLL path (Room for the null terminator + is included in systemdirlen) */ + size_t filenamelen = _tcslen(filename); + TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen)); + if(path && GetSystemDirectory(path, systemdirlen)) { + /* Calculate the full DLL path */ + _tcscpy(path + _tcslen(path), TEXT("\\")); + _tcscpy(path + _tcslen(path), filename); + + /* Load the DLL from the Windows system directory */ + hModule = pLoadLibraryEx ? + pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : + LoadLibrary(path); + + free(path); + } + } + } + + return hModule; +} + +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +#endif /* WIN32 */ diff --git a/lib/system_win32.h b/lib/system_win32.h new file mode 100644 index 000000000..dec18899a --- /dev/null +++ b/lib/system_win32.h @@ -0,0 +1,39 @@ +#ifndef HEADER_CURL_SYSTEM_WIN32_H +#define HEADER_CURL_SYSTEM_WIN32_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2016, Steve Holme, . + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#if defined(WIN32) + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + +/* This is used to dynamically load DLLs */ +HMODULE Curl_load_library(LPCTSTR filename); + +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +#endif /* WIN32 */ + +#endif /* HEADER_CURL_SYSTEM_WIN32_H */ diff --git a/lib/telnet.c b/lib/telnet.c index 6b73bc5bd..870a1b825 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -51,6 +51,7 @@ #include "telnet.h" #include "connect.h" #include "progress.h" +#include "system_win32.h" #define TELOPTS #define TELCMDS @@ -1334,7 +1335,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* OK, so we have WinSock 2.0. We need to dynamically */ /* load ws2_32.dll and get the function pointers we need. */ - wsock2 = LoadLibrary(TEXT("WS2_32.DLL")); + wsock2 = Curl_load_library(TEXT("WS2_32.DLL")); if(wsock2 == NULL) { failf(data, "failed to load WS2_32.DLL (%d)", ERRNO); return CURLE_FAILED_INIT; diff --git a/packages/Symbian/group/libcurl.mmp b/packages/Symbian/group/libcurl.mmp index be22fda5e..f74b19b53 100644 --- a/packages/Symbian/group/libcurl.mmp +++ b/packages/Symbian/group/libcurl.mmp @@ -39,7 +39,7 @@ SOURCE \ asyn-ares.c asyn-thread.c curl_gssapi.c http_ntlm.c curl_ntlm_wb.c \ curl_ntlm_core.c curl_sasl.c vtls/schannel.c curl_multibyte.c \ vtls/darwinssl.c conncache.c curl_sasl_sspi.c smb.c curl_endian.c \ - curl_des.c \ + curl_des.c system_win32.c \ vauth/vauth.c vauth/cleartext.c vauth/cram.c vauth/digest.c \ vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c \ vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c \