Windows 7 UAC whitelist:
Proof-of-concept source code

Win7Elevate.exe:

Win7Elevate.dll:

See the detailed description for a step-by-step guide to what the code does.

See the main page for compiled binaries, Visual Studio project, general discussion, etc.

UAC comedy tragedy security theatre

Detailed Description


This file contains supplemental detail about the proof-of-concept code described here: http://www.pretentiousname.com/misc/win7_uac_whitelist2.html.

About the source:

As far as the source goes, Win7Elevate_Inject.cpp is the most interesting file. The rest is mostly utility and GUI code of little interest, except perhaps the little utility class for copying memory from one process to another.

There is more code in the proof-of-concept app than there has to be:

Don't let the amount of code fool you into thinking there's anything complex going on. There isn't really.

About the DLL: You don't need to copy the DLL anywhere because the main EXE contains an embedded copy of it.

Caveats:

The following caveats are because I didn't bother making the code cope with every combination of process types. None of these things are inherently impossible but it didn't seem worth it when I only wanted to prove that my theory worked:

How it works in detail:

The code exploits two flaws. IMO the first is more interesting/important and also harder to fix. The second flaw should be easy to fix, but it's probably also easy to find more flaws like it, so it's less interesting (but should still be fixed).

The first part is what I've explained on my site with some steps added to launch the second part. (Don't worry about what FileA/FolderB/ProgramC are yet.)

The second part involves FileA, FolderB and ProgramC.

FileA is actually Win7ElevateDll(32|64).dll, an extremely simple DLL whose source is included. (dllmain.cpp is the only interesting part of the DLL.) This DLL is embedded as a resource inside the EXE and extracted as needed, so that the EXE remains a standalone program.

As soon as anything attaches to the DLL it will:

So if we can trick an elevated program into loading that DLL then we can run whatever we specify with elevation.

Note: We can write to Program Files and System32, however we cannot (yet) move/rename/replace many of the files in System32. This is because they're owned by TrustedInstaller and need ownership/permission changes before administrators can change them. There might be a COM object waiting to be found which can do that but we certainly don't need it yet.

So, FileA is our dummy DLL...

Originally, FolderB and ProgramC pointed to "C:\Program Files\Windows Media Player\wmpconfig.exe" which was the first item on Rafael's list of auto-elevated programs.

I figured I'd start at the top of the list and it turned out I didn't need to look any further, back when the beta (build 7000) was current.

However, wmpconfig.exe's auto-elevation status was removed in build 7022 so I had to look for another process in Rafael's updated list.

I decided to start at the bottom this time, knowing executables not directly below System32 were most likely to be suitable (I'll explain why in a moment). As before, the first exe I tried worked and I didn't need to look any further. Changing that exe path is the only modification I've had to make since the code was originally written.

For builds from 7022 until 7100 RC1 (and presumably beyond), FolderB and ProgramC point to "C:\Windows\System32\sysprep\sysprep.exe"

How did I know these exes were vulnerable? It took very little time: I loaded Process Monitor and then launched wmpconfig.exe (and later sysprep.exe) to see if it tried & failed to load any DLLs from its own directory before moving on to other directories... Indeed it did, a DLL called CRYPTBASE.DLL.

The real CRYPTBASE.DLL exists in System32 and we cannot currently replace it because of the TrustedInstaller permissions. But we can, using the first/main flaw, copy a fake CRYPTBASE.DLL to sysprep.exe's folder so that sysprep.exe loads our DLL instead of the real one.

(By default when a process loads a DLL it will look in its own folder first and fall back on System32 (etc.) if it wasn't found. Windows has a list of "Known DLLs" which will always be loaded directly from System32 without looking in the exe's own folder first. That list exists to avoid diversions like this and is a good idea. Unfortunately, Microsoft seem to have forgotten to put CRYPTBASE.DLL on the list. Oops. I would have told them this back in February if they had bothered to respond to my repeated offers to give them the full details of this stuff. Instead of putting their heads in the sand. Perhaps there's still time to add CRYPTBASE.DLL to the list and fix the second flaw for the RTM, but I imagine there are other ways to exploit the ability to copy a file to a protected folder. I found the CRYPTBASE.DLL issue in a matter of minutes and didn't bother looking for alternatives..)

So, going back to steps 1.4 and 1.5, the injected code copies our dummy DLL, Win7ElevateDll(32|64).dll, to C:\Windows\System32\sysprep\CRYPTBASE.DLL and then runs sysprep.exe, passing the details of what to run on the command line.

With the Win 7 UAC defaults, sysprep.exe (and about 70 other processes) automatically and silently elevates itself no matter who runs it. It doesn't matter that we launch sysprep.exe from a medium-integrity process; it will elevate itself to high integrity. Note that Microsoft don't allow anyone else's processes to have this ability. Apparently it's alright for Microsoft code to require admin access, without displaying a UAC prompt, but it's not alright for anyone else's code to do the same thing.

Anyway, as soon as sysprep.exe loads our DLL, the DLL takes over, looks up the process's command-line and launches what we told it to. Because sysprep.exe is elevated the thing we launch is also elevated. sysprep.exe is then killed, CRYPTBASE.DLL is deleted (we're polite and wouldn't want to break sysprep!) and we're done.

You may be wondering...

Couldn't we copy sysprep.exe to where the DLL is, instead of copyign the DLL to where sysprep.exe is, to avoid the need to write to a protected folder?

No, is the answer. If you copy an auto-elevated process to another location then it will no longer auto-elevate because UAC no longer recognises its certificate. That is good thinking on Microsoft's part. The automatic/silent elevation stuff only happens for binaries in specially permissioned folders. So Microsoft clearly thought about and tried to avoid this sort of problem, they just didn't do a particularly good job of it, and then they ignored and dismissed someone who tried to tell them about something they missed.