{"id":12313,"date":"2010-11-10T07:00:00","date_gmt":"2010-11-10T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/11\/10\/your-debugging-code-can-be-a-security-vulnerability-loading-optional-debugging-dlls-without-a-full-path\/"},"modified":"2010-11-10T07:00:00","modified_gmt":"2010-11-10T07:00:00","slug":"your-debugging-code-can-be-a-security-vulnerability-loading-optional-debugging-dlls-without-a-full-path","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20101110-00\/?p=12313","title":{"rendered":"Your debugging code can be a security vulnerability: Loading optional debugging DLLs without a full path"},"content":{"rendered":"<p>\nRemember, the bad guys don&#8217;t care that your feature exists\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2005\/12\/12\/502719.aspx\">\njust for debugging purposes<\/a>.\nIf it&#8217;s there, they will attack it.\n<\/p>\n<p>\nConsider the following code:\n<\/p>\n<pre>\nDOCLOADINGPROC g_pfnOnDocLoading;\nvoid LoadDebuggingHooks()\n{\n HMODULE hmodDebug = LoadLibrary(TEXT(\"DebugHooks.dll\"));\n if (!hmodDebug) return;\n g_pfnOnDocLoading = (DOCLOADINGPROC)\n               GetProcAddress(hmodDebug, \"OnDocLoading\");\n ...\n}\nHRESULT LoadDocument(...)\n{\n ...\n if (g_pfnOnDocLoading) {\n   \/\/ let the debugging hook replace the stream\n   g_pfnOnDocLoading(&amp;pstmDoc);\n }\n ...\n}\n<\/pre>\n<p>\nWhen you need to debug the program, you can install the\n<code>DebugHooks.dll<\/code> DLL into the application directory.\nThe code above looks for that DLL and if present, gets\nsome function pointers from it.\nFor illustrative purposes, I&#8217;ve included one debugging hook.\nThe idea of this example\n(and it&#8217;s just an example,\nso let&#8217;s not argue about whether it&#8217;s a good example)\nis that when we&#8217;re about to load a document,\nwe call the <code>OnDocLoading<\/code> function,\ntelling it about the document that was just loaded.\nThe <code>OnDocLoading<\/code> function\nwraps the <code>IStream<\/code> inside another object\nso that the contents of the document can be logged\nbyte-by-byte as it is loaded, in\nan attempt to narrow down exactly where document loading fails.\nOr it can be used for testing purposes to inject I\/O errors\ninto the document loading path to confirm that the program\nbehaves properly under those conditions.\nUse your imagination.\n<\/p>\n<p>\nBut this debugging code is also a security vulnerability.\n<\/p>\n<p>\nRecall that the library search path searches directories\nin the following order:\n<\/p>\n<ol>\n<li>The directory containing the application EXE.\n<\/li>\n<li>The system32 directory.\n<\/li>\n<li>The system directory.\n<\/li>\n<li>The Windows directory.\n<\/li>\n<li>The current directory.\n<\/li>\n<li>The PATH.\n<\/li>\n<\/ol>\n<p>\nWhen debugging your program, you install <code>DebugHooks.dll<\/code>\ninto the application directory so that it is found in step&nbsp;1.\nBut when your program isn&#8217;t being debugged,\nthe search in step&nbsp;1 fails,\nand the search continues in the other directories.\nThe DLL is not found in steps 2&nbsp;through&nbsp;4,\nand then we reach step&nbsp;5: The current directory.\n<\/p>\n<p>\nAnd now you&#8217;re pwned.\n<\/p>\n<p>\nYour application typically does not have direct control over\nthe current directory.\nThe user can run your program from any directory,\nand that directory ends up as your current directory.\nAnd then your <code>LoadLibrary<\/code> call searches\nthe current directory,\nand if a bad guy put a rogue DLL in the current directory,\nyour program just becames the victim of code injection.\n<\/p>\n<p>\nThis is made particularly dangerous when your application\nis associated with a file type,\nbecause the user can run your application just by\ndouble-clicking an associated document.\n<\/p>\n<p>\nWhen you double-click a document, Explorer sets the\ncurrent directory of the document handler application\nto the directory that contains the document being opened.\nThis is necessary for applications which look around\nin the current directory for supporting files.\nFor example,\nconsider\na hypothetical application <code>LitWare Writer<\/code>\nassociated with <code>*.LIT<\/code> files.\nA LitWare Writer document\n<code>ABC.LIT<\/code> file is really just the representative\nfor a family of files,\n<code>ABC.LIT<\/code> (the main document),\n<code>ABC.LTC<\/code> (the document index and table of contents),\n<code>ABC.LDC<\/code> (the custom spell check dictionary for the document),\n<code>ABC.LLT<\/code> (the custom document layout template),\nand so on.\nWhen you open the document <code>C:\\PROPOSAL\\ABC.LIT<\/code>,\nLitWare Writer looks for the other parts of your document\nin the current directory,\nrather than in <code>C:\\PROPOSAL<\/code>.\nTo help these applications find their files,\nExplorer specifies to the <code>CreateProcess<\/code> function\nthat it should set the initial current directory of\nLitWare Writer to <code>C:\\PROPOSAL<\/code>.\n<\/p>\n<p>\nNow, you might argue that programs like LitWare Writer\n(which look for the ancillary files of a multi-file document\nin the current directory instead of the directory containing\nthe primary file of the multi-file document) are\npoorly-written, and I would agree with you,\nbut Windows needs to work even with poorly-written programs.\n(<b>Pre-emptive snarky comment<\/b>: Windows is itself\na poorly-written program.)\nThere are a lot of poorly-written programs out there,\nsome of them industry leaders in their market (<b>see above\npre-emptive snarky comment<\/b>)\nand if Windows stopped accommodating them, people would\nsay it was the fault of Windows and not the programs.\n<\/p>\n<p>\nI can even see in my mind&#8217;s eye the bug report that resulted\nin this behavior being added to the MS-DOS Executive:\n<\/p>\n<p>\n&#8220;This program has worked just fine in MS-DOS,\nbut in Windows, it doesn&#8217;t work.\nStupid Windows.&#8221;\n<\/p>\n<p>\nCustomers tend not to be happy with the reply,\n&#8220;Actually, that program has simply been lucky for the past X years.\nThe authors of the program never considered the case where\nthe document being opened is not in the current directory.\nAnd it got away with it, because the way you opened the document\nwas to use the <code>chdir<\/code> command to move to the directory\nthat contained your document,\nand then to type\n<code>LWW ABC.LIT<\/code>.\nIf you had ever done\n<code>LWW C:\\PROPOSAL\\ABC.LIT<\/code> you would have run into the\nsame problem.\nThe behavior is by design.&#8221;\n<\/p>\n<p>\nIn response to &#8220;The behavior is by design&#8221; is usually\n&#8220;Well, a design that prevents me from getting my work done is\na crappy design.&#8221;\nor a much terser &#8220;No it&#8217;s not, it&#8217;s a bug.&#8221;\n(Don&#8217;t believe me? Just read Slashdot.)\n<\/p>\n<p>\nSo to make these programs work in spite of themselves,\nthe MS-DOS Executive sets the current directory of the program\nbeing launched to the directory containing the document itself.\nThis was not an unreasonable decision because it gets the program\nworking again, and it&#8217;s not like the program cared about the\ncurrent directory it inherited from the MS-DOS Executive,\nsince it had no control over that either!\n<\/p>\n<p>\nBut it means that if you launched a program by double-clicking\nan associated document, then unless that program takes steps to\nchange its current directory, it will have the document&#8217;s containing\nfolder as its current directory, which prevents you from deleting\nthat directory.\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nI wrote this series of entries nearly two years ago,\nand even then,\nI didn&#8217;t consider this to be anything particularly groundbreaking,\nbut apparently some people rediscovered it a few months ago\nand are falling all over themselves to claim credit\nfor having found it first.\nIt&#8217;s like a new generations of teenagers who think they invented sex.\nFor the record, here is some\n<a HREF=\"http:\/\/support.microsoft.com\/kb\/2389418\">\nofficial guidance<\/a>.\n(And just to be clear,\nthat&#8217;s official guidance on the current directory attack,\nnot\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2006\/10\/26\/875991.aspx\">\nofficial guidance on sex<\/a>.)\n<\/p>\n<p>\n<b>History chatter<\/b>:\nWhy is the current directory even considered at all?\nThe answer goes back to CP\/M.\nIn CP\/M, there was no PATH.\nEverything executed from the current directory.\nThe rest is a chain of backward compatibility.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Remember, the bad guys don&#8217;t care that your feature exists just for debugging purposes. If it&#8217;s there, they will attack it. Consider the following code: DOCLOADINGPROC g_pfnOnDocLoading; void LoadDebuggingHooks() { HMODULE hmodDebug = LoadLibrary(TEXT(&#8220;DebugHooks.dll&#8221;)); if (!hmodDebug) return; g_pfnOnDocLoading = (DOCLOADINGPROC) GetProcAddress(hmodDebug, &#8220;OnDocLoading&#8221;); &#8230; } HRESULT LoadDocument(&#8230;) { &#8230; if (g_pfnOnDocLoading) { \/\/ let the debugging [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-12313","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Remember, the bad guys don&#8217;t care that your feature exists just for debugging purposes. If it&#8217;s there, they will attack it. Consider the following code: DOCLOADINGPROC g_pfnOnDocLoading; void LoadDebuggingHooks() { HMODULE hmodDebug = LoadLibrary(TEXT(&#8220;DebugHooks.dll&#8221;)); if (!hmodDebug) return; g_pfnOnDocLoading = (DOCLOADINGPROC) GetProcAddress(hmodDebug, &#8220;OnDocLoading&#8221;); &#8230; } HRESULT LoadDocument(&#8230;) { &#8230; if (g_pfnOnDocLoading) { \/\/ let the debugging [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=12313"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12313\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=12313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=12313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=12313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}