Full Disclosure mailing list archives
Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype
From: "KJK::Hyperion" <hackbunny () s0ftpj org>
Date: Wed, 17 Oct 2007 18:43:12 +0200
KJK::Hyperion ha scritto:
ShellExecute is not called ExecuteUri [...]
This function isn't, either, but it should be close enough: /* --- 8< ------ 8< -SNIP- 8< ------ 8< ------ 8< -SNIP- 8< --- */ /* * Helper functions to unambiguously execute URLs with ShellExecute(Ex). * Author: KJK::Hyperion <hackbunny () s0ftpj org> */ /* * Copyright (c) 2007 KJK::Hyperion * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <shellapi.h> #include <shlwapi.h> #include <wininet.h> #include <strsafe.h> BOOL ShellExecuteURLExInternal(LPSHELLEXECUTEINFO lpExecInfo) { BOOL bRet; DWORD dwErr; HRESULT hr; PARSEDURL pu; TCHAR szSchemeBuffer[INTERNET_MAX_SCHEME_LENGTH + 1]; HKEY hkeyClass; /* Default error codes */ bRet = FALSE; dwErr = ERROR_INVALID_PARAMETER; hr = S_OK; lpExecInfo->hInstApp = (HINSTANCE)UlongToHandle(SE_ERR_ACCESSDENIED); /* Validate parameters */ if ( lpExecInfo->cbSize == sizeof(*lpExecInfo) && lpExecInfo->lpFile != NULL && (lpExecInfo->fMask & SEE_MASK_INVOKEIDLIST) == 0 && (lpExecInfo->fMask & SEE_MASK_CLASSNAME) == 0 && (lpExecInfo->fMask & 0x00400000) == 0 /* SEE_MASK_FILEANDURL */ ) { /* Extract the scheme out of the URL */ pu.cbSize = sizeof(pu); hr = ParseURL(lpExecInfo->lpFile, &pu); /* Is the URL really, unambiguously an URL? */ if ( SUCCEEDED(hr) && pu.pszProtocol == lpExecInfo->lpFile && pu.pszProtocol[pu.cchProtocol] == TEXT(':') ) { /* We need the scheme name NUL-terminated, so we copy it */ hr = StringCbCopyN ( szSchemeBuffer, sizeof(szSchemeBuffer), pu.pszProtocol, pu.cchProtocol * sizeof(TCHAR) ); if(SUCCEEDED(hr)) { /* Is the URL scheme a registered ProgId? */ hr = AssocQueryKey ( ASSOCF_INIT_IGNOREUNKNOWN, ASSOCKEY_CLASS, szSchemeBuffer, NULL, &hkeyClass ); if(SUCCEEDED(hr)) { /* Is the ProgId really an URL scheme? */ dwErr = RegQueryValueEx ( hkeyClass, TEXT("URL Protocol"), NULL, NULL, NULL, NULL ); /* All clear! */ if(dwErr == NO_ERROR || dwErr == ERROR_MORE_DATA) { /* Don't let ShellExecuteEx guess */ lpExecInfo->fMask |= SEE_MASK_CLASSKEY; lpExecInfo->lpClass = NULL; lpExecInfo->hkeyClass = hkeyClass; /* Finally, execute the damn URL */ bRet = ShellExecuteEx(lpExecInfo); /* To preserve ShellExecuteEx's last error */ dwErr = NO_ERROR; } RegCloseKey(hkeyClass); } } } } /* Last error was a HRESULT */ if(FAILED(hr)) { /* Try to dissect it */ if(HRESULT_FACILITY(hr) == FACILITY_WIN32) dwErr = HRESULT_CODE(hr); else dwErr = hr; } /* We have a last error to set */ if(dwErr) SetLastError(dwErr); return bRet; } BOOL ShellExecuteURLEx(LPSHELLEXECUTEINFO lpExecInfo) { BOOL bRet; SHELLEXECUTEINFO ExecInfo; /* We use a copy of the parameters, because you never know */ CopyMemory(&ExecInfo, lpExecInfo, sizeof(ExecInfo)); /* Do the magic */ bRet = ShellExecuteURLExInternal(&ExecInfo); /* These need to be copied back */ lpExecInfo->hInstApp = ExecInfo.hInstApp; lpExecInfo->hProcess = ExecInfo.hProcess; return bRet; } HINSTANCE ShellExecuteURL ( HWND hwnd, LPCTSTR lpOperation, LPCTSTR lpFile, LPCTSTR lpParameters, LPCTSTR lpDirectory, INT nShowCmd ) { SHELLEXECUTEINFO ExecuteInfo; ExecuteInfo.fMask = SEE_MASK_FLAG_NO_UI; /* Odd but true */ ExecuteInfo.hwnd = hwnd; ExecuteInfo.cbSize = sizeof(ExecuteInfo); ExecuteInfo.lpVerb = lpOperation; ExecuteInfo.lpFile = lpFile; ExecuteInfo.lpParameters = lpParameters; ExecuteInfo.lpDirectory = lpDirectory; ExecuteInfo.nShow = nShowCmd; ShellExecuteURLExInternal(&ExecuteInfo); return ExecuteInfo.hInstApp; } /* --- >8 -SNIP- >8 ------ >8 ------ >8 -SNIP- >8 ------ >8 --- */ Developers: when you know you are going to execute an URL, consider using these safe wrappers instead of calling ShellExecute(Ex) directly In case you are curious, they work by looking up the program associated to the URL scheme (and verifying that the scheme is actually registered as such) before calling ShellExecuteEx. This prevents ShellExecuteEx from guessing (wrong), and causes any URL, however broken and mangled, to be passed verbatim to the application that registered to handle it. Using the original PoC as an example, using ShellExecuteURLEx instead of ShellExecuteEx will cause your e-mail program to start composing a mail addressed to Mr. "test%../../../../windows/system32/calc.exe.cmd" (or "test%../../../../windows/system32/calc.exe".cmd", depending on the program. But I think you get the idea) This code will not solve all issues, but it will prevent any dangerous treatment of ambiguous or invalid URLs, and it will ultimately shift the blame for any input validation failure to the external application that receives the URL Even if you won't use my code directly, it will, hopefully, help you understand what happens inside ShellExecuteEx _______________________________________________ Full-Disclosure - We believe in it. Charter: http://lists.grok.org.uk/full-disclosure-charter.html Hosted and sponsored by Secunia - http://secunia.com/
Current thread:
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype, (continued)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Andreas Lindenblatt (Oct 09)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Andreas Lindenblatt (Oct 09)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Thierry Zoller (Oct 06)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Morning Wood (Oct 08)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Paul Szabo (Oct 06)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype KJK::Hyperion (Oct 06)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Paul Szabo (Oct 07)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype KJK::Hyperion (Oct 07)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Paul Szabo (Oct 11)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype KJK::Hyperion (Oct 06)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype Pavel Kankovsky (Oct 12)
- Re: URI handling woes in Acrobat Reader, Netscape, Miranda, Skype KJK::Hyperion (Oct 17)