Sunday, February 17, 2013

Windows File Confusion: Masquerading Unsigned Binaries as Signed Ones

Could it be? A non-PowerShell related blog post?

A while ago, Mark Baggett (@MarkBaggett) tipped me off to a technique that he had seen malware using in the wild. He explained that if you could manage to execute an unsigned binary with the same name as a signed binary (but with trailing white space) that it would take on the code signature of the legitimate binary.

I was obviously intrigued. This posed a bit of a challenge though because Windows automatically strips trailing white space from file names. I eventually figured out how to bypass this slight restriction by echoing the contents of my binary using `type` to a path prefixed with \\?\.

For example, to name the file "evil.exe" to "calc.exe   " (note the three trailing spaces), you would do the following:

type evil.exe > "\\?\C:\Windows\System32\calc.exe   "

Great. We now have an unsigned binary with trailing white space. Now how does one execute it? As is demonstrated by the following screenshot, there is no longer a file association with the binary and Windows doesn't know how to load it.

I asked some friends for ideas on how to execute it and Chris Campbell (@obscuresec) had the genius idea to execute it via its 8.3 file name. Trying to call it directly from cmd.exe with its 8.3 file name unfortunately opened the original, signed calc. However, executing it with the Create method of the Win32_Process WMI class worked like a champ! This was accomplished with the following WMIC command:

wmic process call create C:\Windows\System32\CALC~1.exe

The following screenshot demonstrates the steps necessary to create a binary with trailing white space and consequently execute it:

Upon executing the unsigned file masquerading as the original calc.exe, you notice something amusing - when viewed in Process Explorer, the signed calc.exe is mistaken for the unsigned one and Process Explorer mistakenly reports the unsigned calc as having a valid code signature both in the process and module listings. It doesn't take long to see that something isn't right though. For example: the following differences are evident:

  • The file sizes differ
  • The unsigned binary is a .NET executable. The original calc is not.
  • The unsigned binary is lacking the company name of "Microsoft Corporation". I tried to replicate the company name by modifying the assembly information of my unsigned binary but it caused Process Explorer to no longer say that it was '(Verified) Microsoft Windows'.

Another peculiarity I witnessed was that depending upon how you referenced the file names, the hash of the unsigned binary differed. Its true hash would only be manifested by referring to its 8.3 file name.

All in all, I would consider this technique to be more of a novelty than a serious vulnerability. For example, sigcheck detects the unsigned binary. Also, if code integrity checks are enforced (as Windows RT does), the kernel will prevent the unsigned binary from being executed. The underlying logic flaw is that Microsoft made the assumption that an executable would not have any trailing white space. As a result, the file information of the original executable (with no trailing white space) is processed rather than that of the one with trailing white space.

You can download the binary I used in the screenshots here. All it is is a basic Windows Forms .NET executable with the calc.exe icon and assembly information.


  1. maybe that could be useful for whitelist execution control bypass

  2. My thoughts exactly. I wanted to test it out on AppLocker but it doesn't work on Windows 8 Pro. When I say it doesn't work, you can configure rules and test them but it won't actually enforce them. You need WIndows 8 Enterprise. Grrr. I'll have to see if this will bypass SRP though.

  3. Doesn't work on win7 x64 , although I tried to put my file into C:\program files\eraser\eraser.exe as I wanted to see if both files will run on startup as a method of priv escalation if DIR is writable but file isn't...
    don't know if it makes any difference that I choose some 3rd party app instead of window's application such as calc.exe?

    I get "return value = 9;" :/

  4. It's also interesting that Microsoft Security Essentials fails to scan the file :))
    I didn't try on other AVs though...

  5. Tested on AppLocker on Windows 7 Ultimate and, as expected, the correct executable (evil.exe / calc~1.exe) is detected. The event log records shows however \windows\system32\calc.exe as file name, but what else could it show?

  6. same deal on createProcess i get retvalue 9. This is on Server 2008 R2 to test SRP bypass - what OS did you run this on successfully?