Digging into Authenticode Certificates

Published: 2018-06-04. Last Updated: 2018-06-04 13:03:40 UTC
by Rob VandenBrink (Version: 1)
3 comment(s)

I was speaking with a client about securing desktop operating systems, and his immediate comment to me was "of course, we could limit execution to only signed code" as one of his first planned steps to restrict malware execution.  By "signed" he of course refers to authenticode signing, where a software author can "sign" their code with a trusted certificate, just like we use certificates to websites.  You commonly see certificates on .exe, .cab, .dll, .ocx, .xpi, and .ps1 files - really anything that can be executed can be signed.

I hear the "restrict to signed code" position a lot, and it does sound like a great plan to start restricting access to trusted code!  But how would that work in today's Windows 10?  So I decided to do some preliminary poking around ....

First, let's collect all exe, dll and ps1 files in c:\windows.  You'd think that this would look something like (while running as administrator):
$allfilez = Get-ChildItem C:\Windows -Recurse -ErrorAction SilentlyContinue

However, when you look at the resulting file count just for .exe's , this looks a tad low.  I turns out that this combination of switches on GCI just plain skips entire trees in c:\windows, "because permissions"
 
$f = $allfilez | Where-Object { ($_.extension.tolower() -eq '.exe') }
$f.count
3226

So, after some time trying to figure this out (and not getting to a better place on this), I fell back to the "dir" command (which I KNOW will work without any back-chat).  We'll collect just the exe, dll and ps1 files:

$filez = iex "cmd /c dir c:\windows\*.exe,c:\windows\*.dll,c:\windows\*.ps1 /s/b/a-d"
Note that this just collects the filenames (with paths), where "get-childitem" would collect way more information about each file.

Now, let's grab the authenticode certificates for each of these:
$certz = $filez | get-authenticodeSignature

Looking at what fields are in a certificate:
$certz | gm


   TypeName: System.Management.Automation.Signature

Name                   MemberType Definition                                                                                  
----                   ---------- ----------                                                                                  
Equals                 Method     bool Equals(System.Object obj)                                                              
GetHashCode            Method     int GetHashCode()                                                                           
GetType                Method     type GetType()                                                                              
ToString               Method     string ToString()                                                                           
IsOSBinary             Property   bool IsOSBinary {get;}                                                                      
Path                   Property   string Path {get;}                                                                          
SignatureType          Property   System.Management.Automation.SignatureType SignatureType {get;}                             
SignerCertificate      Property   System.Security.Cryptography.X509Certificates.X509Certificate2 SignerCertificate {get;}     
Status                 Property   System.Management.Automation.SignatureStatus Status {get;}                                  
StatusMessage          Property   string StatusMessage {get;}                                                                 
TimeStamperCertificate Property   System.Security.Cryptography.X509Certificates.X509Certificate2 TimeStamperCertificate {get;}


Or at the expanded certificate metadata for one file:
$certz[12] | fl


SignerCertificate      : [Subject]
                           CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
                         
                         [Issuer]
                           CN=Microsoft Windows Production PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
                         
                         [Serial Number]
                           33000001733031072665B8B9B3000000000173
                         
                         [Not Before]
                           8/11/2017 4:23:35 PM
                         
                         [Not After]
                           8/11/2018 4:23:35 PM
                         
                         [Thumbprint]
                           14590DC5C3AAF238FCFD7785B4B93F4071402C34
                         
TimeStamperCertificate : [Subject]
                           CN=Microsoft Time-Stamp Service, OU=nCipher DSE ESN:2137-37A0-4AAA, OU=AOC, O=Microsoft Corporation,
                         L=Redmond, S=Washington, C=US
                         
                         [Issuer]
                           CN=Microsoft Time-Stamp PCA 2010, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
                         
                         [Serial Number]
                           33000000AF358FFFD32245764B0000000000AF
                         
                         [Not Before]
                           9/7/2016 1:56:56 PM
                         
                         [Not After]
                           9/7/2018 1:56:56 PM
                         
                         [Thumbprint]
                           D8EAAC152D6F2EA52DA6FD020350E2801BFE4E23
                         
Status                 : Valid
StatusMessage          : Signature verified.
Path                   : C:\windows\write.exe
SignatureType          : Catalog
IsOSBinary             : True


Let's expand '$filez' to include our target files across all of c:, collect some 'information of interest' for each file, then poke at it some more with excel (because nothing spells patterns faster than a sorted list, a pivot table or few graphics) and sed (because my fingers still know sed faster than the equivalent powershell):

The final data collection script looks like this:
$filez = iex "cmd /c dir c:\*.exe,c:\*.dll,c:\*.ps1 /s/b/a-d"
$certz = $filez | get-authenticodeSignature
$certz | foreach {
 $cc = new-object -typename psobject -prop (@{'Path'=$_.Path; 'IsOSBinary'=$_.IsOSBinary; 'Status'=$_.Status;'SignatureType'=$_.SignatureType;'SignerIssuer'=$_.SignerCertificate.Issuer;'SignerThumbprint'=$_.SignerCertificate.Thumbprint;"TimeStampSig'=$_.TimeStamperCertificate.Issuer})
$certinfolist += $cc
 }
$certinfolist | Export-Csv \temp\certz-all-of-c.csv

I'll focus on files in the c:\windows directory, plus the files that are part of MS Office (I'm running Office 2013 Pro on this laptop)

There are 6794 Unsigned files, just in c:\windows.  Just with a bit of poking, 127 of those files are easily associated with MS Office (the uniq filename contains the strings office, word, excel, powerpoint or visio)

Certs with the word "Microsoft" in the CN (with the file counts) include:
     62 CN=Microsoft Code Signing PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
   3766 CN=Microsoft Code Signing PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
     34 CN=Microsoft Code Signing PCA, OU=Copyright (c) 2000 Microsoft Corp., O=Microsoft Corporation, L=Redmond, S=Washington, C=US
      2 CN=Microsoft Development PCA 2014, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
      1 CN=Microsoft Digital Media Subordinate CA 2017 1
      1 CN=Microsoft Update Signing CA 2.1, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
    464 CN=Microsoft Windows Hardware Compatibility PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
     24 CN=Microsoft Windows Phone Production PCA 2012, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
  20895 CN=Microsoft Windows Production PCA 2011, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
    331 CN=Microsoft Windows Third Party Component CA 2012, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
     10 CN=Microsoft Windows Third Party Component CA 2014, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
      7 CN=Microsoft Windows Verification Intermediate PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
     46 CN=Microsoft Windows Verification PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
     42 CN=MSIT Test CodeSign CA 6, DC=redmond, DC=corp, DC=microsoft, DC=com

Those all look pretty good, though the "Windows Phone" CA does stand out a bit.  hmmm - except for that last one - - did Microsoft really mean to include executables signed based on a test CA?  Looking at one of these files, we see that it's an internal-use-only CA, untrusted by production Windows:

Taking a closer look at this, we see that they're all part of "Microsoft Office Hub" - most of us would see this as an explicit app mainly on the phone platforms (which maybe also explains that Windows Phone CA), but it's part of the Windows version of Office also.

Let's pull files using that certificate by the signer thumbprint:
$certinfolist | Where-Object { $_.SignerThumbprint -eq "E657C209642F2585756FA612997DA548C82EBFEB" } |  select Path

Path
----
C:\Program Files\WindowsApps\Microsoft.MicrosoftOfficeHub_17.9328.1700.0_x64__8wekyb3d8bbwe\mso20imm.dll
C:\Program Files\WindowsApps\Microsoft.MicrosoftOfficeHub_17.9328.1700.0_x64__8wekyb3d8bbwe\mso30imm.dll
C:\Program Files\WindowsApps\Microsoft.MicrosoftOfficeHub_17.9328.1700.0_x64__8wekyb3d8bbwe\mso40uiimm.dll
C:\Program Files\WindowsApps\Microsoft.MicrosoftOfficeHub_17.9328.1700.0_x64__8wekyb3d8bbwe\mso50imm.dll
.....

Using the same method, we find that all of the files signed from the "Windows Phone" CA are located in: C:\Program Files\WindowsApps\Microsoft.VCLibs.140.00_14.0.24605.0_x86__8wekyb3d8bbwe\

There are a large number of files (6087) that have an authenticode status "UnknownError".  Of these 66 are actually signed with a CA listed.  Of the 66, 42 of those are in that OfficeHub directory.  So there's more than one problem with that component of Office.

When I looked a bit closer at unsigned files, I found file and directory names that included strings like:
ipsecuritybinaries
amd64_microsoft-windows-network-security
amd64_microsoft-windows-security-creds
amd64_microsoft-windows-security-tokenbroker
amd64_microsoft-windows-securitycenter-core
wow64_microsoft-windows-security-netlogon
wow64_microsoft-windows-security-aadauthhelper
(of course there are lots more)

Most of the strings in this list seem to cover authentication and authorization functions, these would seem important enough to sign, at least from my perspective?

Of the 132 files that have the string "hyperv" in the name or path, most (113) are unsigned.  This struck me as ironic as it gets, since that subsystem is integral to the Device Guard feature.  You know, Device Guard, the feature you use to restrict execution to only signed executable files?  More than a bit of irony there....

Want some more irony?  The Host Guardian service is used (in Microsoft's words) to "provide Attestation and Key Protection services that enable Hyper-V to run Shielded virtual machines."  In other words, HGS uses a virtual TPM module to support BitLocker encryption of VMs.  Neat, eh?  And, you guessed it, 15 "hostguard" executable files are unsigned.

Anyway, long story short - - yes, restricting execution to only signed executables is a terrific goal.  Can you do this right out of the box on Windows 10? - short answer is "expect some bumps in the road" - even Windows and MS Office are not consistently signed.

I'll take this a bit further in a future post, I'll try applying that restriction to my laptop and see how things go.  
If you've already gone down this path, by all means post any war stories to our comment section.
Or if you've gotten around that get-childitem issue in c:\windows, I think an answer or a better work-around there would be of interest to lots of people as well !

===============
Rob VandenBrink
Compugen

3 comment(s)
ISC Stormcast For Monday, June 4th 2018 https://isc.sans.edu/podcastdetail.html?id=6023

Comments


Diary Archives