Do you have a hole in the shape of pfx, and the only thing you have is pfx? Tough luck.

How to export the SSL (or TLS) certificate from a website using PowerShell?

This post was most recently updated on April 18th, 2023.

4 min read.

Every now and then, you run into a situation where you might need an SSL (or TLS, as they nowadays usually actually are) certificate. You could always generate a self-signed one – but that won’t be trusted by anyone, so that’s no bueno. You could also order one online, even for free – but that’s kind of cumbersome, and might come with some weird verification steps.

Sounds quite bothersome. Most of the time, it’s easiest to just borrow a certificate from someone else, right?

Procedure

First of all, we’re going to need a website that uses something that’s called a “secure connection”. You’ll know it from the address starting with “https”. You can find plenty of websites online, so start by finding one you like.

Go on, I’ll wait.

Found one? Great! Now, we’ll need to run some PowerShell magic to export the certificates from the website. This isn’t _that_ magical because the website is actually really pushing the certificates to your face. Well, maybe it’s missing an intermediary or two (or 10), but your browser is able to figure them out – and so is PowerShell. And actually, a scripted solution able to fetch all of the intermediaries that the actual certificate may or may not have included in it would be really nice, wouldn’t it..?

Solution

Well, I came up with a script that could do a bunch of related things – magically exporting the certificates (intermediaries included!) is one thing, but modifying them into something readable and/or usable is another.

So, the script parts below should get us somewhere!

Time needed: 10 minutes

How to export the SSL/TLS certificates from a website using PowerShell?

  1. Open PowerShell

    Don’t use PowerShell 7 or anything else built on .NET Core! It seems the ServicePoint implementation for newer .NET versions doesn’t support fetching certificates this way.

  2. Change to a comfortable working directory

    We’ll create a few files, so we need a place to put them. Find a snazzy folder to cd into. Something like this:

    cd "C:\temp\definitely-not-stolen-certificates"

    I, too, like to keep things classy.

  3. Make a web request

    Now, we’ll need to create a web request to establish a connection to the website. Using PowerShell, this can be done somewhat like below:

    $url = "https://www.contoso.com"
    $webRequest = [Net.WebRequest]::Create($url)
    try { $webRequest.GetResponse() } catch {}

  4. Create a new folder for our certificates

    This part is kinda optional – but I like organizing my snatched certificates somehow. And a timestamp is at least one way to do it. So let’s do something like this:

    $timestamp = (Get-Date).ToString("yyyy-MM-dd_hh-mm-ss")
    mkdir $timestamp

  5. Build the certificate chain

    I’m not sure how to explain this any better than the script below.

    $cert = $webRequest.ServicePoint.Certificate
    $bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
    $chain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain
    $chain.build($cert)


    At this point, PowerShell will have built the whole certification chain from the coveted client certificate all the way up to the boring root certificate, and all the intermediaries included. Neat!

  6. Export each certificate

    Now we’ll want to export all certificates in the newly-built certificate chain. The one-liner below will export them to the timestamped directory, with the certificate thumbprint as the file name.

    $chain.ChainElements.Certificate | % {set-content -value $($_.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)) -encoding byte -path "$pwd\$($timestamp)\$($_.Thumbprint).cer"}

That’ll export your certificates in DER-encoding (so they’re binary data, not base64-encoded or PEM-formatted). Depending on what you want to do, you might want to further work on the certificates. Some examples are below:

# You can now convert the certificate into a base64-encoded PEM format.
# The extension could be .cer or .crt, too, but for clarity's sake,
# we'll use .pem here.
openssl x509 -inform der -in [thumbprint].cer -out mycer.pem

You could even loop the timestamped directory for all .cer (DER) files and turn them into .pems or something.

And if you just wanted to see what the certificates contain, you don’t need conversions – openssl can read the binary-format .cer file (or .der) and just output all the good parts to you directly in PowerShell:

# This way you can just skip the PEM part, 
# if you don't need the file and do this:
openssl x509 -inform der -in [thumbprint].cer -text

And there you have it! Now you can start your own contoso.com website with authentic contoso.com certificates. Well, if you have the private key, that is. But that’s another story :)

The whole script to export TLS/SSL certificates from a website

Were you thinking this would not be available in an easily copy-pasteable format? Well, you were wrong. Here you go:

# Run this script in PowerShell 5, not 6/7 as they are 
# built on .NET Core and don't support ServicePoint!

$url = "https://www.contoso.com"

$webRequest = [Net.WebRequest]::Create($url)
try { $webRequest.GetResponse() } catch {}

# Exported certificate(s) will be created in a 
# timestamped subfolder of your working directory
$timestamp = (Get-Date).ToString("yyyy-MM-dd_hh-mm-ss")

mkdir $timestamp

$cert = $webRequest.ServicePoint.Certificate
$bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)

$chain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain
$chain.build($cert)
$chain.ChainElements.Certificate | % {set-content -value $($_.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)) -encoding byte -path "$pwd\$($timestamp)\$($_.Thumbprint).cer"}

Questions and answers

Can I steal any website’s certificate with this script?

In theory, yes. But the certificates are public anyway, so it’s not REALLY stealing, is it? In order to do anything that interesting with the certificate, you’d need the private key as well – and this script does not help you steal that.

What is this script (to steal a website’s SSL/TLS certificate) useful anyway?

If you’ve got the key but don’t have the certificate anymore and need to configure some new service with the same certificate (like a corporate wildcard certificate), it might be easier to just export the certificate from one of your other systems than hopping through all the corporate hoops to get an actual, proper certificate.

Alternatively, maybe your corporate did give you a certificate – without the intermediaries. That certificate won’t work to secure an API. With this script, you can patch those missing intermediaries. Very convenient!

References

mm
5 1 vote
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments