Today’s tutorial is nothing new, but I just thought I’d share some recent experience with Microsoft’s PowerShell. I’ve been playing around with PowerShell (PS) for a little while now, nothing too extravagant. I’m not an administrator, so I don’t have hundreds of little tasks I have to do on a daily basis (unless I can write a script to help me wake up and get ready in the morning.. C:\>Set-TeethClean ? ) – Anyways, I was recently assigned the rudimentary task of searching through the Windows Certificate store and finding all CAs that were signed with MD5. If MD5 rings a bell it’s most likely because of this.

I really didn’t want to go through the list one by one, double-clicking, then selecting the Details tab. So, I decided there had to be an easy way to parse this information. My first idea was to fire up Visual Studio and write a quick C# app to do this as it has built-in Certificate Store classes/functions. This seemed too cumbersome, but I still wanted to leverage the .NET framework for the same features. PowerShell it was then.

After a quick look, I found that PS has a built in Cert provider. This was great news, as this allows you to navigate the Cert Store just as if it were a standard file system.

First, I need to tell PS to use the Certificate Provider.

PS C:\>cd Cert:
PS cert:\>

That’s it (there are seven other providers built in, more info can be found here).

Next, we can begin to navigate to where we want to go. You would do this the exact same way you would a regular file system (and with PS you can do this the DOS or Unix way).

PS C:\> cd cert:
PS cert:\> ls
Location   : CurrentUser
 StoreNames : {Simp Untrusted, SmartCardRoot, UserDS, AuthRoot...}
Location   : LocalMachine
 StoreNames : {Simp Untrusted, SmartCardRoot, AuthRoot, CA...}
PS cert:\> cd CurrentUser
 PS cert:\CurrentUser> ls
Name : Simp Untrusted
Name : SmartCardRoot
Name : UserDS
Name : AuthRoot
Name : CA
Name : addressbook
Name : Trust
Name : Disallowed
Name : teststore
Name : My
Name : Root
Name : TrustedPeople
Name : Simp Trusted
Name : ACRS
Name : TrustedPublisher

For my task, I wanted to view all CA certs, so I continued to the CA path.

PS cert:\CurrentUser> cd CA
 PS cert:\CurrentUser\CA>

This happens to be the bottom level of this directory, so doing a directory listing will now give you the individual certs. However, if you’re not at the bottom level of a directory and still want all the certs recursively displayed, you can use the “-recurse” option.

PS cert:\CurrentUser> ls -recurse

If you would like a cleaner output, you can format it with the “format-list” option and even select only the properties you want.

PS cert:\CurrentUser> ls -recurse | format-list -property Thumbprint, Subject, SignatureAlgorithm
Thumbprint         : E9857D5FA133AEC0F8F766ECF59A581E4AB53B29
 Subject            : CN=Gemini Security Certification Authority, DC=gemsec, DC=com
 SignatureAlgorithm : System.Security.Cryptography.Oid

As you’ll see in the sample output, I get the thumbprint, the subject, and the SignatureAlgorithm (SA) (which is one of the key properties my original task is requiring me to filter on). But you’ll notice that the value for the SA is odd. It’s actually returning the object type instead of the value. This is because this is an actual object where Thumbprint and Subject were simply strings. This is how PS handles everything in an object format.

My first thought to actually get a value out of this was to simply parse down the object hierarchy and ask for the values of the lowest properties. SignatureAlgorithm.FriendlyName is the property I actually wanted.

PS cert:\CurrentUser> ls -recurse | format-list -property Thumbprint, Subject, SignatureAlgorithm.FriendlyName
Thumbprint : E9857D5FA133AEC0F8F766ECF59A581E4AB53B29
 Subject    : CN=Gemini Security Certification Authority, DC=gemsec, DC=com

As you can see, the results aren’t exactly what I wanted. I didn’t like my attempt at parsing the object in the filter parameters. It looks like I’m going to have to do something else. Because I knew PS handles everything as objects, I decided to start playing with this list of certs as objects. So, I went and dumped all the certs into a variable

PS cert:\CurrentUser\CA> $AllCerts = ls

Again, that’s it. $AllCerts now holds all the certs in the CA directory. PS automatically detects the type of our objects and creates a collection to store them.

From here, I can parse this collection just like I would any other in .NET or as if I was working in C#. To continue on with the task I need, I want to filter out and return only the certs that have been signed with MD5. So, I’m going to need to loop through each item, check its property, and if it matches, spit it out.

PS cert:\CurrentUser\ca> foreach($c in $AllCerts) { if($c.SignatureAlgorithm.FriendlyName = "md5RSA"){Write-Host $c.Subject}}

Ok, this is kind of a lot if you’re not a programmer or can’t read code strapped out to a single line. What’s happening is I’m looping through all the items in $AllCerts, I’m checking to see if the SA.FriendlyName is equal to “md5RSA”, if it is, I’m outputting the Subject line to the display. Go ahead, try it yourself.

You’ll notice the output is pretty ugly still. In order to make this friendlier for myself, I decided to throw the output to a file instead. This is one of the things I love about PS, how easy it is to write to a file.

PS C:\> ${C:\file.txt} = "this is text being written to the file"

That’s all it takes to write to a file. Use the variable indicator, and enclose your file name in brackets {}. Then, set its value as if it were a standard variable. So for my purposes, I now changed my script to read:

PS cert:\CurrentUser\ca> foreach($c in $AllCerts) { if($c.SignatureAlgorithm.FriendlyName = "md5RSA"){${C:\md5list.txt} += $c.Subject + "`n" }}

The += is to append each line one after another, and the + “`n” is the newline terminator in PS. So after running that, I now have a fresh new file on my root directory that has all the cert subject lines listed out one after another on a separate line.

Mission accomplished!

Once I completed this, I thought maybe I’d use it at some other point in time, so I ended up creating a function:

function GetCertsBySignatureType($type){
$AllCerts = ls Cert:\CurrentUser\ -recurse
foreach($c in $AllCerts){
if($c.SignatureAlgorithm.FriendlyName = $type){
${C:\certlist.txt} += ( $c.Subject + "`n")}}

This way, I just specify the type of cert I’m looking for, and it’s outputted to the list.

PS C:\>GetCertsBySignatureType("md5RSA")

P.S. – This is by no means the only way to do this. I simply decided to share my thought process and final results to you and hoped maybe I’d teach you a little about PowerShell and some of its capabilities. This is an easy add-on to any Vista+ machine, and it even comes default on Microsoft Windows Server 2008.

Each Tuesday, Security Musings features a topic to help educate our readers about security. For more information about Gemini Security Solutions’ security education capabilities, contact us!