Good explanation is here.
- A protected admin can run a non-elevated process which injects a thread into a process such as Explorer (an OS application that’s almost always running and has the IFileCopy COM control loaded).
- The remote thread creates a temporary dll in the same folder as a built-in application binary that’s not under system32 and that’s blessed to silently elevate (i.e. the new Windows 7 UAC behavior). An example is sysprep.exe. The name of the dll must correspond to one that’s not on the “known dlls” list.
- The remote thread launches the application (e.g. sysprep.exe), which ends up loading the trojan dll for its local folder. The trojan is now running elevated.
A few comments:
A response from Microsoft is here. They’re right in saying that the issue above requires getting code running locally which, reading between the lines, almost always means that the security game is lost. However, I also agree with the security researchers who respond that UAC prompts are supposed to mitigate those risks, and in the above case, the user never sees one.
The worst offense is that the UAC whitelist is internal-only. That is, in a managed desktop environment, an IT professional can’t deploy a program that requires elevation in such a way that it won’t prompt. I.e., he can’t reproduce the behavior of built-in applications like sysprep.exe (it’s because the feature requires Microsoft’s code signing certificate). If Microsoft really wanted to get itself into PR trouble over this, applying a double-standard to its most contentious feature (i.e. UAC), which is also the feature that’s proven to be the worst for application compatibility, was a good way to do it.
The known-dlls issue is secondary, but still interesting. I believe that it’s for performance reasons that that list needs to be kept very short, since I suspect that the list of dlls that only can load from system32 may also be the list of dlls that, by default, also load into every process. So if that list gets long, system perf would tank. Now, I may be wrong that those are the same list, but in any case, I can’t see why every OS dll shouldn’t be on a list that only loads from system32 (and only when explicitly loaded).