diff options
author | Steve Holme <steve_holme@hotmail.com> | 2016-05-29 22:57:40 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2016-05-30 08:14:27 +0200 |
commit | 6df916d751e72fc9a1febc07bb59c4ddd886c043 (patch) | |
tree | 4719db7dad6c1a8068988e22f5569a120a602091 /lib | |
parent | ddf25f6b28c944702792b9555d47cdeb8217fece (diff) | |
download | curl-6df916d751e72fc9a1febc07bb59c4ddd886c043.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/Makefile.vc6 | 3 | ||||
-rw-r--r-- | lib/curl_sspi.c | 7 | ||||
-rw-r--r-- | lib/system_win32.c | 130 | ||||
-rw-r--r-- | lib/system_win32.h | 39 | ||||
-rw-r--r-- | lib/telnet.c | 3 |
6 files changed, 179 insertions, 7 deletions
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, <daniel@haxx.se>, et al.
+# Copyright (C) 1999 - 2016, Daniel Stenberg, <daniel@haxx.se>, 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, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, 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 <curl/curl.h> #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, <steve_holme@hotmail.com>. + * + * 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 <curl/curl.h> +#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, <steve_holme@hotmail.com>. + * + * 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; |